github b4403f3d2851 cached
100 files
271.6 KB
68.2k tokens
346 symbols
1 requests
Download .txt
Showing preview only (307K chars total). Download the full file or copy to clipboard to get everything.
Repository: AnyRTC/RTMPCHybridEngine-Android
Branch: github
Commit: b4403f3d2851
Files: 100
Total size: 271.6 KB

Directory structure:
gitextract_zej5ynzh/

├── .gitignore
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── org/
│       │           └── ar/
│       │               └── rtmpc/
│       │                   └── ApplicationTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── ar/
│       │   │           ├── ARApplication.java
│       │   │           ├── BaseActivity.java
│       │   │           ├── DeveloperInfo.java
│       │   │           ├── SplashActivity.java
│       │   │           ├── adapter/
│       │   │           │   ├── AudioLineAdapter.java
│       │   │           │   ├── LiveLineAdapter.java
│       │   │           │   ├── LiveListAdapter.java
│       │   │           │   ├── LiveMessageAdapter.java
│       │   │           │   └── LogAdapter.java
│       │   │           ├── guest/
│       │   │           │   ├── AudioGuestActivity.java
│       │   │           │   ├── GuestActivity.java
│       │   │           │   └── LiveListActivity.java
│       │   │           ├── hoster/
│       │   │           │   ├── AudioHosterActivity.java
│       │   │           │   ├── HosterActivity.java
│       │   │           │   └── LineFragment.java
│       │   │           ├── model/
│       │   │           │   ├── LineBean.java
│       │   │           │   ├── LiveBean.java
│       │   │           │   └── MessageBean.java
│       │   │           ├── utils/
│       │   │           │   ├── ARUtils.java
│       │   │           │   ├── DisplayUtils.java
│       │   │           │   ├── MD5.java
│       │   │           │   ├── NameUtils.java
│       │   │           │   ├── PermissionsCheckUtil.java
│       │   │           │   ├── ScreenUtils.java
│       │   │           │   └── ToastUtil.java
│       │   │           └── widgets/
│       │   │               ├── ARVideoView.java
│       │   │               ├── AppBaseDialogFragment.java
│       │   │               ├── BaseDialog.java
│       │   │               ├── CustomDialog.java
│       │   │               └── KeyboardDialogFragment.java
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── push_bottom_in.xml
│       │       │   └── push_bottom_out.xml
│       │       ├── color/
│       │       │   └── select_text_host_input.xml
│       │       ├── drawable/
│       │       │   ├── bg_host_head.xml
│       │       │   ├── bg_list_item.xml
│       │       │   ├── bg_white.xml
│       │       │   ├── default_input_bg.xml
│       │       │   ├── line_anim.xml
│       │       │   ├── list_item_bg.xml
│       │       │   ├── selector_apply.xml
│       │       │   ├── shape_creat_btn_bg.xml
│       │       │   ├── shape_edittext_bg.xml
│       │       │   ├── shape_home_green_btn.xml
│       │       │   ├── shape_meet_id.xml
│       │       │   ├── shape_message.xml
│       │       │   ├── shape_popuwindow.xml
│       │       │   ├── shape_room_apply_audio_line.xml
│       │       │   ├── shape_room_apply_line.xml
│       │       │   ├── shape_room_hang_up_line.xml
│       │       │   ├── shape_room_member.xml
│       │       │   ├── shape_room_message.xml
│       │       │   └── shape_room_name.xml
│       │       ├── drawable-xxhdpi/
│       │       │   ├── selector_video_manager.xml
│       │       │   ├── shape_back_btn.xml
│       │       │   ├── shape_index_button.xml
│       │       │   └── shape_index_solid_button.xml
│       │       ├── layout/
│       │       │   ├── activity_audio_guest.xml
│       │       │   ├── activity_audio_hoster.xml
│       │       │   ├── activity_guest.xml
│       │       │   ├── activity_hoster.xml
│       │       │   ├── activity_live_list.xml
│       │       │   ├── dialog_base.xml
│       │       │   ├── dialogfragment_keyboard.xml
│       │       │   ├── empty_act_data.xml
│       │       │   ├── empty_no_line_data.xml
│       │       │   ├── fragment_line.xml
│       │       │   ├── item_audio_line.xml
│       │       │   ├── item_line.xml
│       │       │   ├── item_line_list.xml
│       │       │   ├── item_live.xml
│       │       │   ├── item_live_chat.xml
│       │       │   ├── item_member.xml
│       │       │   ├── item_more_futures.xml
│       │       │   └── layout_arvideo.xml
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── ids.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── values-w820dp/
│       │           └── dimens.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── ar/
│                       └── rtmpc/
│                           └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
#

*.iml.gradle/
local.properties/
.idea
.DS_Store
/build
/captures

### Android
template

# Built application files
*.apk
*.ap_

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# Intellij
.idea/
workspace.xml

# Keystore files
*.jks

================================================
FILE: README.md
================================================
# 重要提醒
anyRTC 对该版本已经不再维护。[前往新版本](https://github.com/anyRTC/ArAndroidSDK).

**新版本功能如下:**
- 频道管理
- 音频管理
- 视频管理
- 音频文件播放及混音
- 音效文件播放管理
- CDN推流
- 本地推流CDN组件
- 本地播放器组件
- 跨频道流媒体转发
- 直播导入在线媒体流
- 视频双流模式
- 音频自采集自渲染
- 视频自采集自渲染
- 耳返功能
- 。。。

**公司网址: [www.anyrtc.io](https://www.anyrtc.io)**

### anyRTC-RTMPC-Android SDK for Android
### 简介
基于RTMP和RTC混合引擎的在线视频连麦互动直播

Android 直播(网络自适应码率RTMP publisher)、点播播放器(播放器经过专业优化,可实现秒开RTMP Player)、基于RTMP和RTC混合引擎的视频连麦互动(最多支持4人同时互动)

### 优势
- 商业级开源代码,高效稳定 超小内存占有率,移动直播针对性极致优化,代码冗余率极低 
- iOS,Web,PC全平台适配,硬件编解码可保证99%的可用性
- 接口极简,推流:2个 拉流:2个
- 底层库C++核心库代码风格采用:Google code style
- 极简内核,无需再去深扒复杂的FFMpeg代码
- OpenH264软件编码,FFMpeg软件解码,FAAC/FAAD软件编解码,适配不同系统的硬件编解码统统包含
- 支持SRS、Nginx-RTMP等标准RTMP服务;同时支持各大CDN厂商的接入




### app体验

##### [点击下载](http://download.anyrtc.io/xuye)

### SDK集成
# > 方式一[ ![Download](https://api.bintray.com/packages/dyncanyrtc/ar_dev/rtmpc/images/download.svg) ](https://bintray.com/dyncanyrtc/ar_dev/rtmpc/_latestVersion)

添加Jcenter仓库 Gradle依赖:

```
dependencies {
  compile 'org.ar:rtmpc_hybrid:3.1.1'
}
```

或者 Maven
```
<dependency>
  <groupId>org.ar</groupId>
  <artifactId>rtmpc_hybrid</artifactId>
  <version>3.1.1</version>
  <type>pom</type>
</dependency>
```


##### 编译环境

AndroidStudio

##### 运行环境

Android API 16+
真机运行

### 如何使用

##### 注册开发者信息

>如果您还未注册anyRTC开发者账号,请登录[anyRTC官网](http://www.anyrtc.io)注册及获取更多的帮助。

##### 替换开发者账号
在[anyRTC官网](http://www.anyrtc.io)获取了应用ID,应用Token后,替换DEMO中
**DeveloperInfo**类中的信息即可。推拉流地址需用自己的

### 操作步骤

1. 演示需要两部以及两部以上的手机,装上该demo.
2. 一部手机创建直播间,另外两部手机在主页,下拉刷新当前直播列表,点击列表进入直播间。
3. 游客端点击链接按钮,进行连麦。

### 完整文档
SDK集成,API介绍,详见官方完整文档:[点击查看](https://docs.anyrtc.io/v1/RTMPC/android.html)

### iOS 版 互动连麦

[AR-RTMPC-iOS](https://github.com/AnyRTC/anyRTC-RTMPC-iOS)


### 支持的系统平台
**Android** 4.0及以上

### 支持的CPU架构
**Android** arm64-v8a  armeabi armeabi-v7a


### 注意事项
1. RTMPC SDK所有回调均在子线程中,所以在回调中操作UI等,应切换主线程。
2. 注意安卓6.0+动态权限处理。
3. 常见错误代码请参考[错误码查询](https://www.anyrtc.io/resoure)


### 技术支持 
- anyRTC官方网址:[https://www.anyrtc.io](https://www.anyrtc.io/resoure)
- QQ技术咨询群:554714720
- 联系电话:021-65650071-816
- Email:hi@dync.cc

### 关于直播

本公司有一整套完整直播解决方案。本公司开发者平台www.anyrtc.io。除了基于RTMP协议的直播系统外,我公司还有基于WebRTC的时时交互直播系统、P2P呼叫系统、会议系统等。快捷集成SDK,便可让你的应用拥有时时通话功能。欢迎您的来电~

### License

- RTMPCEngine is available under the MIT license. See the LICENSE file for more info.





   



 


================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    buildToolsVersion '27.0.3'
    defaultConfig {
        applicationId "org.ar.rtmpc"
        minSdkVersion 16
        targetSdkVersion 28
        versionCode 1
        versionName "3.0.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    repositories {
        flatDir {
            dirs 'libs'
        }
    }
}
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:28.0.0'
    compile 'com.android.support:recyclerview-v7:28.0.0'
    compile 'com.android.support:cardview-v7:28.0.0'
    compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.22'
    compile 'com.gyf.barlibrary:barlibrary:2.3.0'
    compile 'com.yanzhenjie.permission:support:2.0.1'
    compile 'com.jaredrummler:material-spinner:1.1.0'
    compile 'com.android.support:design:28.0.0'
    compile 'com.orhanobut:logger:1.15'
    compile 'com.yanzhenjie.nohttp:okhttp:1.1.11'
    compile 'org.ar:rtmpc_hybrid:3.1.0'
    compile 'com.loopj.android:android-async-http:1.4.9'
}


================================================
FILE: app/gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Mar 15 15:28:49 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip


================================================
FILE: app/gradlew
================================================
#!/usr/bin/env sh

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
    echo "$*"
}

die () {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
  NONSTOP* )
    nonstop=true
    ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Escape application args
save () {
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
    echo " "
}
APP_ARGS=$(save "$@")

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
  cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"


================================================
FILE: app/gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\Android\android-sdk-windows/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}
-keepattributes InnerClasses
-dontoptimize
-optimizationpasses 7
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*


-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService


-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * extends android.app.Activity {
    public void *(android.view.View);
}

-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

-keepattributes *Annotation*
-keepattributes Exceptions,InnerClasses,Signature
-keepattributes SourceFile,LineNumberTable

-keep class **.R$* { *; }
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep interface android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.app.Fragment

-keep class org.anyrtc.model.** { *; }


#anyrtc
-dontwarn org.anyrtc.rtmpc_hybrid.**
-keep class org.anyrtc.rtmpc_hybrid.**{*;}
-dontwarn org.webrtc.**
-keep class org.webrtc.**{*;}


 -keep class com.gyf.barlibrary.* {*;}

  #Andprermission
 -keepclassmembers class ** {
     @com.yanzhenjie.permission.PermissionYes <methods>;
 }
 -keepclassmembers class ** {
     @com.yanzhenjie.permission.PermissionNo <methods>;
 }
 #BaseAdapter
 -keep class com.chad.library.adapter.** {
    *;
 }

================================================
FILE: app/src/androidTest/java/org/ar/rtmpc/ApplicationTest.java
================================================
package org.ar.rtmpc;

import android.app.Application;
import android.test.ApplicationTestCase;

/**
 * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
 */
public class ApplicationTest extends ApplicationTestCase<Application> {
    public ApplicationTest() {
        super(Application.class);
    }
}

================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.ar.rtmpc">

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-feature android:name="android.hardware.camera.flash" />
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />


    <application
        android:name="org.ar.ARApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name="org.ar.hoster.HosterActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:windowSoftInputMode="adjustPan" />
        <activity
            android:name="org.ar.guest.GuestActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:windowSoftInputMode="adjustPan" />
        <activity
            android:name="org.ar.guest.AudioGuestActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:windowSoftInputMode="adjustPan" />
        <activity
            android:name="org.ar.hoster.AudioHosterActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:windowSoftInputMode="adjustPan" />
        <activity
            android:name="org.ar.guest.LiveListActivity"
            android:screenOrientation="portrait" />
        <activity android:name="org.ar.SplashActivity"
            android:theme="@style/SplashTheme"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

================================================
FILE: app/src/main/java/org/ar/ARApplication.java
================================================
package org.ar;

import android.app.Application;

import com.yanzhenjie.nohttp.InitializationConfig;
import com.yanzhenjie.nohttp.NoHttp;

import org.ar.utils.NameUtils;
import org.ar.rtmpc_hybrid.ARRtmpcEngine;

/**
 * Created by Skyline on 2016/8/3.
 */
public class ARApplication extends Application {

    public static ARApplication mARApplication;
    private static String NickName="";
    public static String LIVE_ID=(int)((Math.random()*9+1)*100000)+"";//直播间ID

    @Override
    public void onCreate() {
        super.onCreate();
        mARApplication =this;
        NickName= NameUtils.getNickName();
        ARRtmpcEngine.Inst().initEngine(getApplicationContext(), DeveloperInfo.APPID, DeveloperInfo.APPTOKEN);


        InitializationConfig  config = InitializationConfig.newBuilder(this)
                .connectionTimeout(15*1000)
                .readTimeout(15*1000)
                .retry(1).build();
        NoHttp.initialize(config);
    }
    public  static Application App(){
        return mARApplication;
    }

    public static String getNickName(){
        return NickName;
    }

}


================================================
FILE: app/src/main/java/org/ar/BaseActivity.java
================================================
package org.ar;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.gyf.barlibrary.ImmersionBar;

/**
 * Created by Skyline on 2016/5/24.
 */
public abstract class BaseActivity extends AppCompatActivity {
    protected ImmersionBar mImmersionBar;
    ProgressDialog pd;
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(this.getLayoutId());
        mImmersionBar = ImmersionBar.with(this);
        mImmersionBar.statusBarDarkFont(true,0.2f).init();
        this.initView(savedInstanceState);
    }
    private void ProgressDialog(Context ctx) {
        pd = new ProgressDialog(ctx);
        pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        pd.setCancelable(true);
        pd.setCanceledOnTouchOutside(false);
        pd.show();
    }
    public void showProgressDialog() {
        if (pd == null) {
            ProgressDialog(this);
        }
        pd.setMessage("正在加载...");
        pd.show();
    }

    public void hiddenProgressDialog() {
        if (pd != null && pd.isShowing()) {
            pd.cancel();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mImmersionBar != null)
            mImmersionBar.destroy();
    }


    @Override
    public void setContentView(int layoutResID) {
        super.setContentView(layoutResID);
    }


    public void startAnimActivity(Class<?> cls) {
        startActivity(new Intent(this, cls));
    }

    public void finishAnimActivity() {
        finish();
    }

    public void startAnimActivity(Class<?> cls, Bundle bundle) {
        Intent intent = new Intent(this, cls);
        intent.putExtras(bundle);
        startActivity(intent);
    }

    public abstract int getLayoutId();

    public abstract void initView(Bundle savedInstanceState);

}


================================================
FILE: app/src/main/java/org/ar/DeveloperInfo.java
================================================
package org.ar;



public class DeveloperInfo {




    public final static String APPID = "";

    public final static String APPTOKEN = "";

    public final static String PULL_URL = "";

    public final static String PUSH_URL= "";


}


================================================
FILE: app/src/main/java/org/ar/SplashActivity.java
================================================
package org.ar;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

import org.ar.guest.LiveListActivity;

public class SplashActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startActivity(new Intent(this,LiveListActivity.class));
        finish();
    }
}


================================================
FILE: app/src/main/java/org/ar/adapter/AudioLineAdapter.java
================================================
package org.ar.adapter;

import android.view.View;
import android.widget.TextView;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;

import org.ar.rtmpc.R;
import org.ar.model.LineBean;

/**
 * Created by liuxiaozhong on 2017-09-25.
 */

public class AudioLineAdapter extends BaseQuickAdapter<LineBean,BaseViewHolder> {
    boolean isHost;
    public AudioLineAdapter(boolean isHost) {
        super(R.layout.item_audio_line);
        this.isHost=isHost;
    }

    @Override
    protected void convert(BaseViewHolder helper, LineBean item) {
        TextView hangup=helper.getView(R.id.tv_hangup);
        helper.setText(R.id.tv_name,item.name);
        helper.addOnClickListener(R.id.tv_hangup);
        if (isHost){
            hangup.setVisibility(View.VISIBLE);
        }else {
            if (item.isSelf){
                hangup.setVisibility(View.VISIBLE);
            }else {
                hangup.setVisibility(View.INVISIBLE);
            }
        }
    }

}


================================================
FILE: app/src/main/java/org/ar/adapter/LiveLineAdapter.java
================================================
package org.ar.adapter;

import android.widget.TextView;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;

import org.ar.rtmpc.R;
import org.ar.model.LineBean;

/**
 * Created by liuxiaozhong on 2017/9/24.
 */

public class LiveLineAdapter extends BaseQuickAdapter<LineBean,BaseViewHolder> {
    public LiveLineAdapter() {
        super(R.layout.item_line);
    }

    @Override
    protected void convert(BaseViewHolder helper, LineBean item) {
        TextView tv_name=helper.getView(R.id.tv_name);
        tv_name.setText(item.name+"申请连麦");
        helper.addOnClickListener(R.id.tv_agree);
        helper.addOnClickListener(R.id.tv_refuse);
    }
}


================================================
FILE: app/src/main/java/org/ar/adapter/LiveListAdapter.java
================================================
package org.ar.adapter;

import android.graphics.drawable.Drawable;
import android.widget.TextView;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;

import org.ar.rtmpc.R;
import org.ar.model.LiveBean;


/**
 * Created by liuxiaozhong on 2017-09-14.
 */

public class LiveListAdapter extends BaseQuickAdapter<LiveBean,BaseViewHolder> {

    public LiveListAdapter() {
        super(R.layout.item_live);
    }

    @Override
    protected void convert(BaseViewHolder helper, LiveBean item) {
        helper.setText(R.id.tv_name,item.getmLiveTopic());
        helper.setText(R.id.tv_num,item.getmMemberNum()+"");
        TextView tvLiveType = helper.getView(R.id.tv_live_type);

        Drawable imgVideo = helper.itemView.getContext().getResources().getDrawable(
                R.drawable.img_video);
        Drawable imgAdudio = helper.itemView.getContext().getResources().getDrawable(
                R.drawable.img_audio);
        if(item.isAudioLive==1) {
            tvLiveType.setCompoundDrawablesWithIntrinsicBounds(imgAdudio,
                    null, null, null);
            tvLiveType.setText("音频直播");
        } else {
            tvLiveType.setCompoundDrawablesWithIntrinsicBounds(imgVideo,
                    null, null, null);
            tvLiveType.setText("视频");
        }
    }
}


================================================
FILE: app/src/main/java/org/ar/adapter/LiveMessageAdapter.java
================================================
package org.ar.adapter;

import android.graphics.Color;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;

import org.ar.model.MessageBean;

/**
 * Created by liuxiaozhong on 2017-09-22.
 */

public class LiveMessageAdapter extends BaseQuickAdapter<MessageBean, BaseViewHolder> {
    public LiveMessageAdapter() {
        super(android.R.layout.simple_list_item_1);
    }

    @Override
    protected void convert(BaseViewHolder helper, MessageBean item) {
        helper.setTextColor(android.R.id.text1, item.type==1 ? Color.parseColor("#ffffff") : Color.parseColor("#666666"));
        helper.setText(android.R.id.text1, item.name+":"+item.content);
    }
}


================================================
FILE: app/src/main/java/org/ar/adapter/LogAdapter.java
================================================
package org.ar.adapter;

import android.graphics.Color;
import android.widget.TextView;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;

/**
 * Created by liuxiaozhong on 2019/3/12.
 */
public class LogAdapter extends BaseQuickAdapter<String,BaseViewHolder> {
    public LogAdapter() {
        super(android.R.layout.simple_list_item_1);
    }

    @Override
    protected void convert(BaseViewHolder helper, String item) {
        TextView textView=helper.getView(android.R.id.text1);
        textView.setTextColor(Color.parseColor("#666666"));
        helper.setText(android.R.id.text1,item);
    }
}


================================================
FILE: app/src/main/java/org/ar/guest/AudioGuestActivity.java
================================================
package org.ar.guest;

import android.content.DialogInterface;
import android.graphics.drawable.AnimationDrawable;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.chad.library.adapter.base.BaseQuickAdapter;

import org.ar.BaseActivity;
import org.ar.ARApplication;
import org.ar.adapter.AudioLineAdapter;
import org.ar.adapter.LiveMessageAdapter;
import org.ar.adapter.LogAdapter;
import org.ar.common.utils.ARAudioManager;
import org.ar.model.LineBean;
import org.ar.model.MessageBean;
import org.ar.utils.ARUtils;
import org.ar.utils.ToastUtil;
import org.ar.widgets.KeyboardDialogFragment;
import org.ar.common.enums.ARVideoCommon;
import org.ar.rtmpc_hybrid.ARRtmpcEngine;
import org.ar.rtmpc_hybrid.ARRtmpcGuestEvent;
import org.ar.rtmpc_hybrid.ARRtmpcGuestKit;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Set;

/**
 * 音频游客界面
 */
public class AudioGuestActivity extends BaseActivity implements BaseQuickAdapter.OnItemChildClickListener {
    TextView tvTitle;
    RecyclerView rvMsgList,rvLog;
    TextView tvApplyLine;
    View viewSpace;
    TextView tvMemberNum;
    RecyclerView rvLineList;
    TextView tvRtmpOk;
    TextView tvRtmpStatus;
    TextView tvRtcOk;
    TextView tvHostName;
    ImageView ivLineAnim;
    RelativeLayout rl_log_layout;
    private ARRtmpcGuestKit mGuestKit;
    private ARAudioManager mRtmpAudioManager = null;
    private LiveMessageAdapter mAdapter;
    private LogAdapter logAdapter;
    private boolean isApplyLine = false;//是否在连麦、申请连麦
    private boolean isLinling = false;
    private AnimationDrawable hostAnimation;
    private AudioLineAdapter audioLineAdapter;
    private String liveId = "";
    private String userID="guest"+(int)((Math.random()*9+1)*100000)+"";

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (isApplyLine) {
                ShowExitDialog();
                return false;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        /**
         * 销毁rtmp播放器
         */
        if (mGuestKit != null) {
            mGuestKit.clean();
            mGuestKit = null;
        }
        if (mRtmpAudioManager != null) {
            mRtmpAudioManager.stop();
            mRtmpAudioManager = null;
        }

    }


    @Override
    public int getLayoutId() {
        return org.ar.rtmpc.R.layout.activity_audio_guest;
    }

    @Override
    public void initView(Bundle savedInstanceState) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); //保持屏幕常亮
        viewSpace = findViewById(org.ar.rtmpc.R.id.view_space);
        mImmersionBar.titleBar(viewSpace).init();
        tvTitle = findViewById(org.ar.rtmpc.R.id.tv_title);
        rl_log_layout=findViewById(org.ar.rtmpc.R.id.rl_log_layout);
        rvLog=findViewById(org.ar.rtmpc.R.id.rv_log);
        rvMsgList = findViewById(org.ar.rtmpc.R.id.rv_msg_list);
        tvApplyLine = findViewById(org.ar.rtmpc.R.id.tv_apply_line);
        tvMemberNum = findViewById(org.ar.rtmpc.R.id.tv_member_num);
        rvLineList = findViewById(org.ar.rtmpc.R.id.rv_line_list);
        tvRtmpOk = findViewById(org.ar.rtmpc.R.id.tv_rtmp_ok);
        tvRtmpStatus = findViewById(org.ar.rtmpc.R.id.tv_rtmp_status);
        tvRtcOk = findViewById(org.ar.rtmpc.R.id.tv_rtc_ok);
        tvHostName = findViewById(org.ar.rtmpc.R.id.tv_host_name);
        ivLineAnim = findViewById(org.ar.rtmpc.R.id.iv_line_anim);
        hostAnimation = (AnimationDrawable) ivLineAnim.getBackground();
        rvMsgList.setLayoutManager(new LinearLayoutManager(this));
        mAdapter = new LiveMessageAdapter();
        audioLineAdapter = new AudioLineAdapter(false);
        audioLineAdapter.setOnItemChildClickListener(this);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        rvLineList.setLayoutManager(linearLayoutManager);
        rvLineList.setAdapter(audioLineAdapter);
        rvLineList.setItemAnimator(null);
        rvMsgList.setAdapter(mAdapter);
        logAdapter = new LogAdapter();
        rvLog.setLayoutManager(new LinearLayoutManager(this));
        logAdapter.bindToRecyclerView(rvLog);
        String pullUrl = getIntent().getStringExtra("pullURL");
        String hostName=getIntent().getStringExtra("hostName");
        tvHostName.setText(hostName);
        liveId = getIntent().getStringExtra("liveId");
        tvTitle.setText("房间ID:" + liveId);
        mRtmpAudioManager = ARAudioManager.create(this);
        mRtmpAudioManager.start(new ARAudioManager.AudioManagerEvents() {
            @Override
            public void onAudioDeviceChanged(ARAudioManager.AudioDevice audioDevice, Set<ARAudioManager.AudioDevice> set) {

            }
        });
        ARRtmpcEngine.Inst().getGuestOption().setMediaType(ARVideoCommon.ARMediaType.Audio);
        mGuestKit = new ARRtmpcGuestKit(mGuestListener);
        mGuestKit.startRtmpPlay(pullUrl, 0);
        mGuestKit.joinRTCLine("", liveId, userID, getUserData());
    }

    public String getUserData() {
        JSONObject user = new JSONObject();
        try {
            user.put("isHost", 0);
            user.put("userId", userID);
            user.put("nickName", ARApplication.getNickName());
            user.put("headUrl", "www.baidu.com");

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return user.toString();
    }

    private void onAudioManagerChangedState() {
        // TODO(henrika): disable video if
        // AppRTCAudioManager.AudioDevice.EARPIECE
        // is active.
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
    }

    private void ShowExitDialog() {
        AlertDialog.Builder build = new AlertDialog.Builder(this);
        build.setTitle(org.ar.rtmpc.R.string.str_exit);
        build.setMessage(org.ar.rtmpc.R.string.str_line_hangup);
        build.setPositiveButton(org.ar.rtmpc.R.string.str_ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                mGuestKit.hangupRTCLine();
                isApplyLine = false;
                isLinling = false;
                finishAnimActivity();
            }
        });
        build.setNegativeButton(org.ar.rtmpc.R.string.str_cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });

        build.show();
    }


    /**
     * 更新列表
     *
     * @param chatMessageBean
     */
    private void addChatMessageList(MessageBean chatMessageBean) {
        // 150 条 修改;

        if (chatMessageBean == null) {
            return;
        }

        if (mAdapter.getData().size() < 150) {
            mAdapter.addData(chatMessageBean);
        } else {
            mAdapter.remove(0);
            mAdapter.addData(chatMessageBean);
        }
        rvMsgList.smoothScrollToPosition(mAdapter.getData().size() - 1);
    }
    public void printLog(String log){
        Log.d("RTMPC", log);
        logAdapter.addData(log);
    }

    /**
     * 观看直播回调信息接口
     */
    private ARRtmpcGuestEvent mGuestListener = new ARRtmpcGuestEvent() {

        /**
         * rtmp 连接成功 视频即将播放;视频播放前的操作可以在此接口中进行操作
         */
        @Override
        public void onRtmpPlayerOk() {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerOk");
                    if (tvRtmpOk != null) {
                        tvRtmpOk.setText("Rtmp连接成功");
                    }
                }
            });
        }

        /**
         * rtmp 开始播放 视频开始播放
         */
        @Override
        public void onRtmpPlayerStart() {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerStart");
                }
            });
        }

        /**
         * rtmp 当前播放状态
         * @param cacheTime 当前缓存时间
         * @param curBitrate 当前播放器码流
         */
        @Override
        public void onRtmpPlayerStatus(final int cacheTime, final int curBitrate) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerStatus cacheTime:" + cacheTime + " curBitrate:" + curBitrate);
                    if (tvRtmpStatus != null) {
                        tvRtmpStatus.setText("当前缓存时间:" + cacheTime + " ms" + "\n当前码流:" + curBitrate / 10024 / 8 + "kb/s");
                    }
                }
            });
        }

        /**
         * rtmp 播放缓冲区时长
         * @param nPercent 缓冲时间
         */
        @Override
        public void onRtmpPlayerLoading(final int nPercent) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerCache  nPercent:" + nPercent);
                }
            });
        }

        /**
         * rtmp 播放器关闭
         * @param nCode
         */
        @Override
        public void onRtmpPlayerClosed(final int nCode) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerClosed  nCode:" + nCode);
                }
            });
        }


        /**
         * 游客RTC 状态回调
         * @param nCode 回调响应码:0:正常;101:主播未开启直播;
         */
        @Override
        public void onRTCJoinLineResult(final int nCode, String s) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCJoinLineResult  nCode:" + nCode);
                    if (nCode == 0) {
                        if (tvRtcOk != null) {
                            tvRtcOk.setText(org.ar.rtmpc.R.string.str_rtc_connect_success);
                        }
                    } else if (nCode == 101) {
                        Toast.makeText(AudioGuestActivity.this, org.ar.rtmpc.R.string.str_hoster_not_live, Toast.LENGTH_LONG).show();
                        if (tvRtcOk != null) {
                            tvRtcOk.setText(org.ar.rtmpc.R.string.str_rtc_connect_success);
                        }
                    } else {
                        if (tvRtcOk != null) {
                            tvRtcOk.setText(ARUtils.getErrString(nCode));
                        }
                    }
                }
            });
        }

        /**
         * 游客申请连线结果
         * @param nCode 0:申请连线成功;-1:主播拒绝连线
         */
        @Override
        public void onRTCApplyLineResult(final int nCode) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCApplyLineResult  nCode:" + nCode);
                    if (nCode == 0) {
                        isApplyLine = true;
                        tvApplyLine.setText("挂断");
                        audioLineAdapter.addData(0, new LineBean("self", "自己", true));
                        isLinling = true;
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_hang_up_line);
                    } else if (nCode == 601) {
                        Toast.makeText(AudioGuestActivity.this, org.ar.rtmpc.R.string.str_hoster_refused, Toast.LENGTH_LONG).show();
                        isApplyLine = false;
                        isLinling = false;
                        tvApplyLine.setText("连麦");
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                    }
                }
            });
        }

        /**
         * 挂断连线回调
         */
        @Override
        public void onRTCHangupLine() {
            //主播连线断开
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCHangupLine ");
                    mGuestKit.hangupRTCLine();
                    audioLineAdapter.remove(0);
                    tvApplyLine.setText(org.ar.rtmpc.R.string.str_connect_hoster);
                    tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                    isApplyLine = false;
                    isLinling = false;
                }
            });
        }


        @Override
        public void onRTCOpenRemoteVideoRender(String s, String s1, String s2, String s3) {

        }

        @Override
        public void onRTCCloseRemoteVideoRender(String s, String s1, String s2) {

        }

        @Override
        public void onRTCOpenRemoteAudioLine(final String strLivePeerId, final String strUserId, final String strUserData) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCOpenAudioLine strLivePeerId:" + strLivePeerId + "strUserId:" + strUserId + " strUserData:" + strUserData);
                    try {
                        JSONObject jsonObject = new JSONObject(strUserData);
                        if (strLivePeerId.equals("RTMPC_Line_Hoster")) {
//                            audioLineAdapter.addData(new LineBean(strLivePeerId, jsonObject.getString("nickName"), true));
                        } else {
                            audioLineAdapter.addData(new LineBean(strLivePeerId, jsonObject.getString("nickName"), false));
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            });
        }

        @Override
        public void onRTCCloseRemoteAudioLine(final String strLivePeerId, final String strUserId) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCCloseAudioLine strLivePeerId:" + strLivePeerId + "strUserId:" + strUserId);
                    int index = 9;
                    for (int i = 0; i < audioLineAdapter.getData().size(); i++) {
                        if (audioLineAdapter.getItem(i).peerId.equals(strLivePeerId)) {
                            index = i;
                        }
                    }
                    if (index != 9 && index <= audioLineAdapter.getData().size()) {
                        audioLineAdapter.remove(index);
                    }
                }
            });
        }

        @Override
        public void onRTCLocalAudioActive(int i) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCLocalAudioActive");
                }
            });
        }

        @Override
        public void onRTCHosterAudioActive(int i) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCHosterAudioActive");
                }
            });
        }


        @Override
        public void onRTCRemoteAudioActive(final String strLivePeerId, final String strUserId, final int nTime) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCAudioActive strLivePeerId:" + strLivePeerId + "strUserId:" + strUserId + " nTime:" + nTime);
                    if (strLivePeerId.equals("RTMPC_Hoster")) {//主播
                        ivLineAnim.setVisibility(View.VISIBLE);
                        hostAnimation.start();
                    } else {
                        for (int i = 0; i < audioLineAdapter.getData().size(); i++) {
                            if (strLivePeerId.equals(audioLineAdapter.getData().get(i).peerId)) {
                                audioLineAdapter.getItem(i).setStartAnim(true);
                                audioLineAdapter.notifyItemChanged(i);
                            }
                        }
                    }
                }
            });
        }

        @Override
        public void onRTCRemoteAVStatus(final String s, boolean b, boolean b1) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCRemoteAVStatus  peerID:" + s);
                }
            });
        }

        /**
         * 主播已离开回调
         * @param nCode
         */
        @Override
        public void onRTCLineLeave(final int nCode, String s) {
            //主播关闭直播
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCLineLeave nCode:" + nCode);
                    if (mGuestKit != null) {
                        mGuestKit.stopRtmpPlay();
                    }
                    finishAnimActivity();
                    ToastUtil.show("主播已离开");
                }
            });
        }


        /**
         * 消息回调
         * @param strCustomID 消息的发送者id
         * @param strCustomName 消息的发送者昵称
         * @param strCustomHeader 消息的发送者头像url
         * @param strMessage 消息内容
         */
        @Override
        public void onRTCUserMessage(final int nType, final String strCustomID, final String strCustomName, final String strCustomHeader, final String strMessage) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCUserMessage nType:" + nType + "strCustomID:" + strCustomID + "strCustomName:" + strCustomName + "strCustomHeader:" + strCustomHeader + "strMessage:" + strMessage);
                    addChatMessageList(new MessageBean(MessageBean.AUDIO, strCustomName, strMessage));
                }
            });
        }

        /**
         * 观看直播的总人数回调
         * @param totalMembers 观看直播的总人数
         */
        @Override
        public void onRTCMemberNotify(final String strServerId, final String strRoomId, final int totalMembers) {
            AudioGuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCMemberNotify strServerId:" + strServerId + "strRoomId:" + strRoomId + "totalMembers:" + totalMembers);
                    tvMemberNum.setText("在线观看人数" + totalMembers + "");
                }
            });
        }


    };

    public void onClick(View view) {
        switch (view.getId()) {
            case org.ar.rtmpc.R.id.btn_close:
                if (isLinling) {
                    ShowExitDialog();
                } else {
                    finishAnimActivity();
                }
                break;
            case org.ar.rtmpc.R.id.iv_message:
                showChatLayout();
                break;
            case org.ar.rtmpc.R.id.tv_apply_line:
                if (isApplyLine) {
                    if (mGuestKit != null) {
                        mGuestKit.hangupRTCLine();
                        if (isLinling){
                            audioLineAdapter.remove(0);
                        }
                        tvApplyLine.setText("连麦");
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                        isApplyLine = false;
                        isLinling = false;
                    }
                } else {
                    if (mGuestKit != null) {
                        mGuestKit.applyRTCLine();
                        tvApplyLine.setText("挂断");
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_hang_up_line);
                        isApplyLine = true;
                        isLinling = false;
                    }
                }
                break;
            case org.ar.rtmpc.R.id.btn_log:
                rl_log_layout.setVisibility(View.VISIBLE);
                break;
            case org.ar.rtmpc.R.id.ibtn_close_log:
                rl_log_layout.setVisibility(View.GONE);
                break;
        }
    }

    private void showChatLayout() {
        KeyboardDialogFragment keyboardDialogFragment = new KeyboardDialogFragment();
        keyboardDialogFragment.show(getSupportFragmentManager(), "KeyboardDialogFragment");
        keyboardDialogFragment.setEdittextListener(new KeyboardDialogFragment.EdittextListener() {
            @Override
            public void setTextStr(String text) {
                addChatMessageList(new MessageBean(MessageBean.AUDIO, ARApplication.getNickName(), text));
                mGuestKit.sendMessage(0, ARApplication.getNickName(), "", text);
            }

            @Override
            public void dismiss(DialogFragment dialogFragment) {
            }
        });
    }


    @Override
    public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
        switch (view.getId()) {
            case org.ar.rtmpc.R.id.tv_hangup:
                if (mGuestKit != null) {

                    mGuestKit.hangupRTCLine();
                    tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                    tvApplyLine.setText("连麦");
                    audioLineAdapter.remove(0);
                    isApplyLine = false;
                    isLinling = false;
                }
                break;
        }
    }

}


================================================
FILE: app/src/main/java/org/ar/guest/GuestActivity.java
================================================
package org.ar.guest;

import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import org.ar.BaseActivity;
import org.ar.ARApplication;
import org.ar.adapter.LiveMessageAdapter;
import org.ar.adapter.LogAdapter;
import org.ar.common.utils.ARAudioManager;
import org.ar.model.MessageBean;
import org.ar.rtmpc.R;
import org.ar.utils.ARUtils;
import org.ar.utils.ToastUtil;
import org.ar.widgets.ARVideoView;
import org.ar.widgets.KeyboardDialogFragment;
import org.ar.common.enums.ARVideoCommon;
import org.ar.rtmpc_hybrid.ARRtmpcEngine;
import org.ar.rtmpc_hybrid.ARRtmpcGuestEvent;
import org.ar.rtmpc_hybrid.ARRtmpcGuestKit;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.VideoRenderer;

import java.util.Set;

/**
 * 视频游客页面
 */
public class GuestActivity extends BaseActivity {
    RelativeLayout rlRtmpcVideos,rl_log_layout;
    TextView tvTitle;
    TextView tvRtmpOk;
    TextView tvRtmpStatus;
    TextView tvRtcOk;
    RecyclerView rvMsgList,rvLog;
    TextView tvApplyLine;
    View viewSpace;
    TextView tvMemberNum;
    ImageButton ibtnCamera;
    private ARRtmpcGuestKit mGuestKit;
    private ARVideoView mVideoView;
    private ARAudioManager mRtmpAudioManager = null;
    private LiveMessageAdapter mAdapter;
    private LogAdapter logAdapter;
    private boolean isApplyLine = false;//是否申请连麦
    private boolean isLining = false;//是否正在连麦
    private String liveId = "";
    private String userId="guest"+(int)((Math.random()*9+1)*100000)+"";
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (isApplyLine) {
                ShowExitDialog();
                return false;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mRtmpAudioManager != null) {
            mRtmpAudioManager.stop();
            mRtmpAudioManager = null;

        }

        /**
         * 销毁rtmp播放器
         */
        if (mGuestKit != null) {
            mGuestKit.clean();
            mVideoView.removeLocalVideoRender();
            mGuestKit = null;
        }
    }

    @Override
    public int getLayoutId() {
        return org.ar.rtmpc.R.layout.activity_guest;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); //保持屏幕常亮
        super.onCreate(savedInstanceState);
    }


    @Override
    public void initView(Bundle savedInstanceState) {
        viewSpace=findViewById(org.ar.rtmpc.R.id.view_space);
        mImmersionBar.titleBar(viewSpace).init();
        ibtnCamera=findViewById(org.ar.rtmpc.R.id.btn_camare);
        rlRtmpcVideos=findViewById(org.ar.rtmpc.R.id.rl_rtmpc_videos);
        rl_log_layout=findViewById(org.ar.rtmpc.R.id.rl_log_layout);
        rvLog=findViewById(org.ar.rtmpc.R.id.rv_log);
        tvTitle=findViewById(org.ar.rtmpc.R.id.tv_title);
        tvRtmpOk=findViewById(org.ar.rtmpc.R.id.tv_rtmp_ok);
        tvRtmpStatus=findViewById(org.ar.rtmpc.R.id.tv_rtmp_status);
        tvRtcOk=findViewById(org.ar.rtmpc.R.id.tv_rtc_ok);
        rvMsgList=findViewById(org.ar.rtmpc.R.id.rv_msg_list);
        tvApplyLine=findViewById(org.ar.rtmpc.R.id.tv_apply_line);
        tvMemberNum=findViewById(org.ar.rtmpc.R.id.tv_member_num);

        logAdapter = new LogAdapter();
        rvLog.setLayoutManager(new LinearLayoutManager(this));
        logAdapter.bindToRecyclerView(rvLog);
        rvMsgList.setLayoutManager(new LinearLayoutManager(this));
        mAdapter = new LiveMessageAdapter();
        rvMsgList.setAdapter(mAdapter);
        ARRtmpcEngine.Inst().getGuestOption().setDefaultFrontCamera(true);
        ARRtmpcEngine.Inst().getGuestOption().setMediaType(ARVideoCommon.ARMediaType.Video);
        String pullUrl = getIntent().getStringExtra("pullURL");
        liveId = getIntent().getStringExtra("liveId");
        tvTitle.setText("房间ID:" +liveId);
        mVideoView = new ARVideoView( rlRtmpcVideos, ARRtmpcEngine.Inst().egl(), this,false, false);
        mVideoView.setVideoViewLayout(false, Gravity.RIGHT, LinearLayout.VERTICAL);
        mVideoView.setVideoLayoutOnclickEvent(new ARVideoView.VideoLayoutOnclickEvent() {
            @Override
            public void onCloseVideoRender(View view, String strPeerId) {
                /**
                 * 挂断连线
                 */
                mGuestKit.hangupRTCLine();
                mVideoView.removeRemoteRender("LocalCameraRender");
                tvApplyLine.setText(org.ar.rtmpc.R.string.str_connect_hoster);
                tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                isApplyLine = false;
                isLining=false;
            }
        });
        mRtmpAudioManager = ARAudioManager.create(this);
        mRtmpAudioManager.start(new ARAudioManager.AudioManagerEvents() {
            @Override
            public void onAudioDeviceChanged(ARAudioManager.AudioDevice audioDevice, Set<ARAudioManager.AudioDevice> set) {

            }
        });
        ARRtmpcEngine.Inst().getGuestOption().setMediaType(ARVideoCommon.ARMediaType.Video);
        mGuestKit = new ARRtmpcGuestKit(mGuestListener);
        mGuestKit.setAudioActiveCheck(true);
        VideoRenderer render = mVideoView.openLocalVideoRender();
        mGuestKit.startRtmpPlay(pullUrl, render.GetRenderPointer());
        mGuestKit.joinRTCLine("", liveId, userId, getUserData());
    }


    public String getUserData() {
        JSONObject user = new JSONObject();
        try {
            user.put("isHost", 0);
            user.put("userId", userId);
            user.put("nickName", ARApplication.getNickName());
            user.put("headUrl", "www.baidu.com");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return user.toString();
    }

    private void onAudioManagerChangedState() {
        // TODO(henrika): disable video if
        // AppRTCAudioManager.AudioDevice.EARPIECE
        // is active.
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
    }

    private void ShowExitDialog() {
        AlertDialog.Builder build = new AlertDialog.Builder(this);
        build.setTitle(org.ar.rtmpc.R.string.str_exit);
        build.setMessage(org.ar.rtmpc.R.string.str_line_hangup);
        build.setPositiveButton(org.ar.rtmpc.R.string.str_ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                mGuestKit.hangupRTCLine();
                mVideoView.removeRemoteRender("LocalCameraRender");
                finishAnimActivity();
            }
        });
        build.setNegativeButton(org.ar.rtmpc.R.string.str_cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });

        build.show();
    }


    /**
     * 更新列表
     *
     * @param chatMessageBean
     */
    private void addChatMessageList(MessageBean chatMessageBean) {
        // 150 条 修改;

        if (chatMessageBean == null) {
            return;
        }

        if (mAdapter.getData().size() < 150) {
            mAdapter.addData(chatMessageBean);
        } else {
            mAdapter.remove(0);
            mAdapter.addData(chatMessageBean);
        }
        rvMsgList.smoothScrollToPosition(mAdapter.getData().size() - 1);
    }

    public void printLog(String log){
        Log.d("RTMPC", log);
        logAdapter.addData(log);
    }

    /**
     * 观看直播回调信息接口
     */
    private ARRtmpcGuestEvent mGuestListener = new ARRtmpcGuestEvent() {

        /**
         * rtmp 连接成功 视频即将播放;视频播放前的操作可以在此接口中进行操作
         */
        @Override
        public void onRtmpPlayerOk() {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerOk");
                    if (tvRtmpOk != null) {
                        tvRtmpOk.setText("Rtmp连接成功");
                    }
                }
            });
        }

        /**
         * rtmp 开始播放 视频开始播放
         */
        @Override
        public void onRtmpPlayerStart() {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerStart");
                }
            });
        }

        /**
         * rtmp 当前播放状态
         * @param cacheTime 当前缓存时间
         * @param curBitrate 当前播放器码流
         */
        @Override
        public void onRtmpPlayerStatus(final int cacheTime, final int curBitrate) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerStatus cacheTime:" + cacheTime + " curBitrate:" + curBitrate);
                    if (tvRtmpStatus != null) {
                        tvRtmpStatus.setText("当前缓存时间:" + cacheTime + " ms" + "\n当前码流:" + curBitrate / 10024 / 8 + "kb/s");
                    }

                }
            });
        }

        /**
         * rtmp 播放缓冲区时长
         * @param nPercent 缓冲时间
         */
        @Override
        public void onRtmpPlayerLoading(final int nPercent) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerCache  nPercent:" + nPercent);
                }
            });
        }

        /**
         * rtmp 播放器关闭
         * @param nCode
         */
        @Override
        public void onRtmpPlayerClosed(final int nCode) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpPlayerClosed  nCode:" + nCode);
                }
            });
        }


        /**
         * 游客RTC 状态回调
         * @param nCode 回调响应码:0:正常;101:主播未开启直播;
         */
        @Override
        public void onRTCJoinLineResult(final int nCode, String s) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCJoinLineResult  nCode:" + nCode);
                    if (tvRtcOk != null) {
                        if (nCode == 0) {
                            tvRtcOk.setText(org.ar.rtmpc.R.string.str_rtc_connect_success);
                        } else if (nCode == 101) {
                            Toast.makeText(GuestActivity.this, org.ar.rtmpc.R.string.str_hoster_not_live, Toast.LENGTH_LONG).show();
                            tvRtcOk.setText(org.ar.rtmpc.R.string.str_rtc_connect_success);
                        } else {
                            tvRtcOk.setText(ARUtils.getErrString(nCode));
                        }
                    }
                }
            });
        }

        /**
         * 游客申请连线回调
         */
        @Override
        public void onRTCApplyLineResult(final int nCode) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @SuppressLint("MissingPermission")
                @Override
                public void run() {
                    printLog("回调:onRTCApplyLineResult  nCode:" + nCode);
                    if (nCode == 0) {
                        ibtnCamera.setVisibility(View.VISIBLE);
                        isApplyLine = true;
                        isLining = true;
                        tvApplyLine.setText("挂断");
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_hang_up_line);
                        VideoRenderer render = mVideoView.openRemoteVideoRender("LocalCameraRender");
                        mGuestKit.setLocalVideoCapturer(render.GetRenderPointer());
                    } else if (nCode == 601) {
                        Toast.makeText(GuestActivity.this, org.ar.rtmpc.R.string.str_hoster_refused, Toast.LENGTH_LONG).show();
                        isApplyLine = false;
                        ibtnCamera.setVisibility(View.GONE);
                        tvApplyLine.setText("连麦");
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                    }
                }
            });
        }


        /**
         * 挂断连线回调
         */
        @Override
        public void onRTCHangupLine() {
            //主播连线断开
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCHangupLine ");
                    mGuestKit.hangupRTCLine();
                    ibtnCamera.setVisibility(View.GONE);
                    mVideoView.removeRemoteRender("LocalCameraRender");
                    tvApplyLine.setText(org.ar.rtmpc.R.string.str_connect_hoster);
                    tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                    isApplyLine = false;
                    isLining = false;
                }
            });
        }


        @Override
        public void onRTCOpenRemoteVideoRender(final String strLivePeerId, final String strPublishId, final String strUserId, final String strUserData) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCOpenVideoRenderLeave strLivePeerId:" + strLivePeerId + "strUserId:" + strUserId + " strUserData:" + strUserData);
                    final VideoRenderer render = mVideoView.openRemoteVideoRender(strLivePeerId);
                    mGuestKit.setRTCRemoteVideoRender(strPublishId, render.GetRenderPointer());
                }
            });
        }

        @Override
        public void onRTCCloseRemoteVideoRender(final String strLivePeerId, final String strPublishId, final String strUserId) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCCloseVideoRender strLivePeerId:" + strLivePeerId + "strUserId:" + strUserId);
                    if (mGuestKit != null && mVideoView != null ) {
                        mGuestKit.setRTCRemoteVideoRender(strPublishId, 0);
                        mVideoView.removeRemoteRender(strLivePeerId);
                    }
                }
            });
        }

        @Override
        public void onRTCOpenRemoteAudioLine(String s, String s1, String s2) {

        }

        @Override
        public void onRTCCloseRemoteAudioLine(String s, String s1) {

        }

        @Override
        public void onRTCLocalAudioActive(int i) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCLocalAudioActive  ");
                }
            });
        }

        @Override
        public void onRTCHosterAudioActive(int i) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCHosterAudioActive  ");
                }
            });
        }


        @Override
        public void onRTCRemoteAudioActive(final String s, String s1, int i) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCRemoteAudioActive  peerID:" + s);
                }
            });
        }

        @Override
        public void onRTCRemoteAVStatus(final String s, boolean b, boolean b1) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCRemoteAVStatus  peerID:" + s);
                }
            });
        }

        /**
         * 主播已离开回调

         */
        @Override
        public void onRTCLineLeave(final int nCode, String s) {
            //主播关闭直播
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCLineLeave nCode:" + nCode);
                    if (mGuestKit != null) {
                        mGuestKit.stopRtmpPlay();
                    }
                    if (nCode == 0) {
                        ToastUtil.show("主播已离开");
                    } else if (nCode == 100) {
                        ToastUtil.show("网络已断开");
                    }
                    finishAnimActivity();
                }
            });
        }

        /**
         * 连线接通后回调
         * @param strLivePeerId
         */


        /**
         * 连线关闭后图像回调
         * @param strLivePeerId
         */


        /**
         * 消息回调
         * @param strCustomID 消息的发送者id
         * @param strCustomName 消息的发送者昵称
         * @param strCustomHeader 消息的发送者头像url
         * @param strMessage 消息内容
         */
        @Override
        public void onRTCUserMessage(final int nType, final String strCustomID, final String strCustomName, final String strCustomHeader, final String strMessage) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCUserMessage nType:" + nType + "strCustomID:" + strCustomID + "strCustomName:" + strCustomName + "strCustomHeader:" + strCustomHeader + "strMessage:" + strMessage);
                    addChatMessageList(new MessageBean(MessageBean.VIDEO, strCustomName, strMessage));
                }
            });
        }

        /**
         * 观看直播的总人数回调
         * @param totalMembers 观看直播的总人数
         */
        @Override
        public void onRTCMemberNotify(final String strServerId, final String strRoomId, final int totalMembers) {
            GuestActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCMemberNotify strServerId:" + strServerId + "strRoomId:" + strRoomId + "totalMembers:" + totalMembers);
                    if (tvMemberNum != null) {
                        tvMemberNum.setText("在线人数" + totalMembers + "");
                    }


                }
            });
        }

    };

    public void onClick(View view) {
        switch (view.getId()) {
            case org.ar.rtmpc.R.id.btn_close:
                if (isLining) {
                    ShowExitDialog();
                } else {
                    finishAnimActivity();
                }
                break;
            case org.ar.rtmpc.R.id.iv_message:
                showChatLayout();
                break;
            case org.ar.rtmpc.R.id.tv_apply_line:
                if (isApplyLine) {
                    if (mGuestKit != null) {
                        mGuestKit.hangupRTCLine();
                        tvApplyLine.setText("连麦");
                        ibtnCamera.setVisibility(View.GONE);
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_apply_line);
                        mVideoView.removeRemoteRender("LocalCameraRender");
                        isApplyLine = false;
                    }
                } else {
                    if (mGuestKit != null) {
                        mGuestKit.applyRTCLine();
                        tvApplyLine.setText("挂断");
                        tvApplyLine.setBackgroundResource(org.ar.rtmpc.R.drawable.shape_room_hang_up_line);
                        isApplyLine = true;
                    }
                }
                break;
            case org.ar.rtmpc.R.id.btn_log:
                rl_log_layout.setVisibility(View.VISIBLE);
                break;
            case org.ar.rtmpc.R.id.ibtn_close_log:
                rl_log_layout.setVisibility(View.GONE);
                break;
            case R.id.btn_camare:
                mGuestKit.switchCamera();
                break;
        }
    }

    private void showChatLayout() {
        KeyboardDialogFragment keyboardDialogFragment = new KeyboardDialogFragment();
        keyboardDialogFragment.show(getSupportFragmentManager(), "KeyboardDialogFragment");
        keyboardDialogFragment.setEdittextListener(new KeyboardDialogFragment.EdittextListener() {
            @Override
            public void setTextStr(String text) {
                addChatMessageList(new MessageBean(MessageBean.VIDEO, ARApplication.getNickName(), text));
                mGuestKit.sendMessage(0, ARApplication.getNickName(), "", text);
            }

            @Override
            public void dismiss(DialogFragment dialogFragment) {
            }
        });
    }

}


================================================
FILE: app/src/main/java/org/ar/guest/LiveListActivity.java
================================================
package org.ar.guest;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.yanzhenjie.nohttp.NoHttp;
import com.yanzhenjie.nohttp.RequestMethod;
import com.yanzhenjie.nohttp.rest.Response;
import com.yanzhenjie.nohttp.rest.SimpleResponseListener;
import com.yanzhenjie.nohttp.rest.StringRequest;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;

import org.ar.BaseActivity;
import org.ar.ARApplication;
import org.ar.adapter.LiveListAdapter;
import org.ar.hoster.AudioHosterActivity;
import org.ar.hoster.HosterActivity;
import org.ar.rtmpc.BuildConfig;
import org.ar.model.LiveBean;
import org.ar.DeveloperInfo;
import org.ar.utils.MD5;
import org.ar.utils.PermissionsCheckUtil;
import org.ar.utils.ToastUtil;
import org.ar.rtmpc_hybrid.ARRtmpcHttpKit;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class LiveListActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener, BaseQuickAdapter.OnItemClickListener, View.OnClickListener {


    RecyclerView rvList;
    SwipeRefreshLayout swipeRefresh;
    LiveListAdapter mAdapter;
    private List<LiveBean> live_list = new ArrayList<>();
    Button btn_video, btn_audio;
    TextView tvVersion;
    @Override
    public int getLayoutId() {
        return org.ar.rtmpc.R.layout.activity_live_list;
    }

    @Override
    public void initView(Bundle savedInstanceState) {

        tvVersion=findViewById(org.ar.rtmpc.R.id.tv_version);
        tvVersion.setText("v "+ BuildConfig.VERSION_NAME);
        btn_video = findViewById(org.ar.rtmpc.R.id.btn_video);
        btn_audio =  findViewById(org.ar.rtmpc.R.id.btn_audio);
        btn_video.setOnClickListener(this);
        btn_audio.setOnClickListener(this);
        rvList =  findViewById(org.ar.rtmpc.R.id.rv_list);
        swipeRefresh = findViewById(org.ar.rtmpc.R.id.swipe_refresh);
        mAdapter = new LiveListAdapter();
        mAdapter.setOnItemClickListener(this);
        mAdapter.setEmptyView(getEmptyView());
        swipeRefresh.setOnRefreshListener(this);
        rvList.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false));
        rvList.setAdapter(mAdapter);

        AndPermission.with(this).runtime().permission(Permission.RECORD_AUDIO,Permission.CAMERA).start();
    }

    @Override
    protected void onResume() {
        super.onResume();
        getLiveList();
    }

    public View getEmptyView(){
        View view=View.inflate(this, org.ar.rtmpc.R.layout.empty_act_data,null);
        TextView tvReGet= (TextView) view.findViewById(org.ar.rtmpc.R.id.tv_reget);
        tvReGet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getLiveList();
            }
        });
        return view;
    }
    @Override
    public void onRefresh() {
        getLiveList();
    }


    @Override
    public void onItemClick(BaseQuickAdapter adapter, View view, final int position) {
        if (AndPermission.hasPermissions(LiveListActivity.this,Permission.CAMERA,Permission.RECORD_AUDIO)){
                Intent intent = new Intent(LiveListActivity.this, mAdapter.getItem(position).getIsAudioLive()==1 ? AudioGuestActivity.class : GuestActivity.class);
                intent.putExtra("pullURL", mAdapter.getItem(position).getmRtmpPullUrl());
                intent.putExtra("liveId",mAdapter.getItem(position).getmAnyrtcId());
                intent.putExtra("hostName",mAdapter.getItem(position).getmHostName());
                startActivity(intent);
        }else {
            PermissionsCheckUtil.showMissingPermissionDialog(LiveListActivity.this, "请先开启录音和相机权限");
        }
    }

    private void getLiveList() {
        ARRtmpcHttpKit.getAuthLivingList(this, new ARRtmpcHttpKit.RTMPCHttpCallback() {
            @Override
            public void OnRTMPCHttpOK(String s) {
                if (swipeRefresh != null) {
                    swipeRefresh.setRefreshing(false);
                }
                if (TextUtils.isEmpty(s)) {
                    return;
                }
                try {
                    live_list.clear();
                    JSONObject jsonObject = new JSONObject(s);
                    if (jsonObject.has("LiveList")) {
                        JSONArray liveList = jsonObject.getJSONArray("LiveList");
                        JSONArray member = jsonObject.getJSONArray("LiveMembers");
                        for (int i = 0; i < liveList.length(); i++) {
                            JSONObject itemJson = new JSONObject(liveList.getString(i));
                            LiveBean bean = new LiveBean();
                            bean.setmRtmpPullUrl(itemJson.getString("rtmpUrl"));
                            bean.setmHlsUrl(itemJson.getString("hlsUrl"));
                            bean.setmLiveTopic(itemJson.getString("liveTopic"));
                            bean.setIsAudioLive(itemJson.getInt("isAudioLive"));
                            bean.setmAnyrtcId(itemJson.getString("anyrtcId"));
                            bean.setmHostName(itemJson.getString("hosterName"));
                            if (i <= member.length()) {
                                bean.setmMemberNum(member.get(i).toString());
                            }
                            live_list.add(bean);
                        }
                        mAdapter.setNewData(live_list);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }


            }

            @Override
            public void OnRTMPCHttpFailed(int i) {
                ToastUtil.show("获取列表失败");
                if (swipeRefresh != null) {
                    swipeRefresh.setRefreshing(false);
                }
            }
        });
    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case org.ar.rtmpc.R.id.btn_audio:
                if (AndPermission.hasPermissions(LiveListActivity.this,Permission.CAMERA,Permission.RECORD_AUDIO)){
                        Intent intent = new Intent(LiveListActivity.this,  AudioHosterActivity.class);
                        intent.putExtra("pushURL", DeveloperInfo.PUSH_URL);
                        intent.putExtra("pullURL", DeveloperInfo.PULL_URL);
                        startActivity(intent);
                }else {
                    PermissionsCheckUtil.showMissingPermissionDialog(LiveListActivity.this, "请先开启录音和相机权限");
                }

                break;
            case org.ar.rtmpc.R.id.btn_video:
                if (AndPermission.hasPermissions(LiveListActivity.this,Permission.CAMERA,Permission.RECORD_AUDIO)){
                        Intent intent = new Intent(LiveListActivity.this,  HosterActivity.class);
                        intent.putExtra("pushURL", DeveloperInfo.PUSH_URL);
                        intent.putExtra("pullURL", DeveloperInfo.PULL_URL);
                        startActivity(intent);
                }else {
                    PermissionsCheckUtil.showMissingPermissionDialog(LiveListActivity.this, "请先开启录音和相机权限");
                }
                break;
        }
    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            System.exit(0);
            finishAnimActivity();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }


}


================================================
FILE: app/src/main/java/org/ar/hoster/AudioHosterActivity.java
================================================
package org.ar.hoster;

import android.content.DialogInterface;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.chad.library.adapter.base.BaseQuickAdapter;

import org.ar.BaseActivity;
import org.ar.ARApplication;
import org.ar.adapter.AudioLineAdapter;
import org.ar.adapter.LiveMessageAdapter;
import org.ar.adapter.LogAdapter;
import org.ar.common.utils.ARAudioManager;
import org.ar.rtmpc.R;
import org.ar.model.LineBean;
import org.ar.model.MessageBean;
import org.ar.utils.ARUtils;
import org.ar.utils.DisplayUtils;
import org.ar.utils.ToastUtil;
import org.ar.widgets.CustomDialog;
import org.ar.widgets.KeyboardDialogFragment;
import org.ar.common.enums.ARVideoCommon;
import org.ar.rtmpc_hybrid.ARRtmpcEngine;
import org.ar.rtmpc_hybrid.ARRtmpcHosterEvent;
import org.ar.rtmpc_hybrid.ARRtmpcHosterKit;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 音频主播页面
 */
public class AudioHosterActivity extends BaseActivity implements BaseQuickAdapter.OnItemChildClickListener {

    TextView tvTitle, tvRtmpOk, tvRtmpStatus, tvRtcOk, tvMemberNum, tv_host_name;
    RecyclerView rvMsgList;
    View viewSpace;
    ImageButton tvLineList;
    RecyclerView rvLineList,rvLog;
    RelativeLayout rl_log_layout;
    private LogAdapter logAdapter;
    private AudioLineAdapter audioLineAdapter;
    private ARRtmpcHosterKit mHosterKit;
    private ARAudioManager mRtmpAudioManager = null;
    private LiveMessageAdapter mAdapter;
    private String nickname;
    private CustomDialog line_dialog;
    private LineFragment lineFragment;
    private boolean isShowLineList = false;
    HosterActivity.LineListener lineListener;
    private String pushURL = "",pullURL="", liveId = ARApplication.LIVE_ID,userId="host"+(int)((Math.random()*9+1)*100000)+"";
    private List<String> applyLineList=new ArrayList<>();//申请连麦的人  这个用于判断小红点显示隐藏

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            ShowExitDialog();
        }
        return false;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mHosterKit != null) {
            mHosterKit.clean();
            mHosterKit = null;
        }

        // Close RTMPAudioManager
        if (mRtmpAudioManager != null) {
            mRtmpAudioManager.stop();
            mRtmpAudioManager = null;

        }


    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_audio_hoster;
    }

    @Override
    public void initView(Bundle savedInstanceState) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        tvTitle = findViewById(R.id.tv_title);
        rl_log_layout=findViewById(R.id.rl_log_layout);
        rvLog=findViewById(R.id.rv_log);
        tvRtmpOk = findViewById(R.id.tv_rtmp_ok);
        tvRtmpStatus = findViewById(R.id.tv_rtmp_status);
        tvRtcOk = findViewById(R.id.tv_rtc_ok);
        rvMsgList = findViewById(R.id.rv_msg_list);
        viewSpace = findViewById(R.id.view_space);
        mImmersionBar.titleBar(viewSpace).init();
        tvMemberNum = findViewById(R.id.tv_member_num);
        tvLineList = findViewById(R.id.tv_line_list);
        rvLineList = findViewById(R.id.rv_line_list);
        tv_host_name = findViewById(R.id.tv_host_name);
        initLineFragment();
        logAdapter = new LogAdapter();
        rvLog.setLayoutManager(new LinearLayoutManager(this));
        logAdapter.bindToRecyclerView(rvLog);
        mAdapter = new LiveMessageAdapter();
        audioLineAdapter = new AudioLineAdapter(true);
        audioLineAdapter.setOnItemChildClickListener(this);
        rvLineList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        rvLineList.setAdapter(audioLineAdapter);
        rvMsgList.setLayoutManager(new LinearLayoutManager(this));
        rvMsgList.setAdapter(mAdapter);
        pushURL = getIntent().getStringExtra("pushURL");
        pullURL=getIntent().getStringExtra("pullURL");
        tvTitle.setText("房间ID:" + liveId);
        nickname = ARApplication.getNickName();
        tv_host_name.setText(nickname);
        mRtmpAudioManager = ARAudioManager.create(this);
        mRtmpAudioManager.start(new ARAudioManager.AudioManagerEvents() {
            @Override
            public void onAudioDeviceChanged(ARAudioManager.AudioDevice audioDevice, Set<ARAudioManager.AudioDevice> set) {

            }
        });
        ARRtmpcEngine.Inst().getHosterOption().setMediaType(ARVideoCommon.ARMediaType.Audio);
        mHosterKit = new ARRtmpcHosterKit(mHosterListener);
        mHosterKit.startPushRtmpStream(pushURL);
        mHosterKit.createRTCLine("", liveId, "host", getUserData(), getLiveInfo(pullURL, pullURL));
    }

    public String getLiveInfo(String pullUrl, String hlsUrl) {
        JSONObject liveInfo = new JSONObject();

        try {
            liveInfo.put("hosterId", userId);
            liveInfo.put("rtmpUrl", pullUrl);
            liveInfo.put("hlsUrl", hlsUrl);
            liveInfo.put("liveTopic", liveId);
            liveInfo.put("anyrtcId", liveId);
            liveInfo.put("isAudioLive", 1);
            liveInfo.put("hosterName", nickname);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return liveInfo.toString();
    }

    public String getUserData() {
        JSONObject user = new JSONObject();
        try {
            user.put("isHost", 1);
            user.put("userId", userId);
            user.put("nickName", ARApplication.getNickName());
            user.put("headUrl", "www.baidu.com");

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return user.toString();
    }

    private void onAudioManagerChangedState() {
        // TODO(henrika): disable video if
        // AppRTCAudioManager.AudioDevice.EARPIECE
        // is active.
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
    }


    /**
     * 更细列表
     *
     * @param chatMessageBean
     */
    private void addChatMessageList(MessageBean chatMessageBean) {
        // 150 条 修改;

        if (chatMessageBean == null) {
            return;
        }

        if (mAdapter.getData().size() < 150) {
            mAdapter.addData(chatMessageBean);
        } else {
            mAdapter.remove(0);
            mAdapter.addData(chatMessageBean);
        }
        rvMsgList.smoothScrollToPosition(mAdapter.getData().size() - 1);
    }

    private void showChatLayout() {
        KeyboardDialogFragment keyboardDialogFragment = new KeyboardDialogFragment();
        keyboardDialogFragment.show(getSupportFragmentManager(), "KeyboardDialogFragment");
        keyboardDialogFragment.setEdittextListener(new KeyboardDialogFragment.EdittextListener() {
            @Override
            public void setTextStr(String text) {
                addChatMessageList(new MessageBean(MessageBean.AUDIO, nickname, text));
                mHosterKit.sendMessage(0, nickname, "", text);
            }

            @Override
            public void dismiss(DialogFragment dialogFragment) {
            }
        });
    }


    private void ShowExitDialog() {
        AlertDialog.Builder build = new AlertDialog.Builder(this);
        build.setTitle(R.string.str_exit);
        build.setMessage(R.string.str_live_stop);
        build.setPositiveButton(R.string.str_ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                finishAnimActivity();
            }
        });
        build.setNegativeButton(R.string.str_cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });

        build.show();
    }
    public void printLog(String log){
        Log.d("RTMPC", log);
        logAdapter.addData(log);
    }

    /**
     * 主播回调信息接口
     */
    private ARRtmpcHosterEvent mHosterListener = new ARRtmpcHosterEvent() {
        /**
         * rtmp连接成功
         */
        @Override
        public void onRtmpStreamOk() {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamOk");
                    if (tvRtmpOk != null) {
                        tvRtmpOk.setText("RTMP连接成功");
                    }
                }
            });
        }

        /**
         * rtmp 重连次数
         * @param times 重连次数
         */
        @Override
        public void onRtmpStreamReconnecting(final int times) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamReconnecting times:" + times);

                }
            });
        }

        /**
         * rtmp 推流状态
         * @param delayMs 推流延时
         * @param netBand 推流码流
         */
        @Override
        public void onRtmpStreamStatus(final int delayMs, final int netBand) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamStatus delayMs:" + delayMs + "netBand:" + netBand);
                    if (tvRtmpStatus != null) {
                        tvRtmpStatus.setText(String.format(getString(R.string.str_rtmp_status), delayMs + "ms", netBand / 1024 / 8 + "kb/s"));
                    }

                }
            });
        }

        /**
         * rtmp推流失败回调
         * @param code
         */
        @Override
        public void onRtmpStreamFailed(final int code) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamFailed code:" + code);
                    if (tvRtmpStatus != null) {
                        tvRtmpStatus.setText("推流失败");
                    }
                }
            });
        }

        /**
         * rtmp 推流关闭回调
         */
        @Override
        public void onRtmpStreamClosed() {
            Log.d("RTMPC", "onRtmpStreamClosed ");
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamClosed ");
                    if (tvRtmpStatus != null) {
                        tvRtmpStatus.setText("RTMP流关闭");
                    }
                }
            });

        }


        /**
         * RTC 连接回调
         * @param code 0: 连接成功
         */
        @Override
        public void onRTCCreateLineResult(final int code, String s) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调: onRTCCreateLineResult  code:" + code);
                    if (code == 0) {
                        if (tvRtcOk != null) {
                            tvRtcOk.setText(R.string.str_rtc_connect_success);
                        }
                    } else {
                        if (tvRtcOk != null) {
                            tvRtcOk.setText(ARUtils.getErrString(code));
                        }
                    }
                }
            });
        }

        /**
         * 游客有申请连线回调
         *
         * @param strLivePeerID
         * @param strCustomID
         * @param strUserData
         */

        @Override
        public void onRTCApplyToLine(final String strLivePeerID, final String strCustomID, final String strUserData) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCApplyToLine  strLivePeerID:" + strLivePeerID + " strCustomID:" + strCustomID + " strUserData:" + strUserData);
                    try {
                        JSONObject jsonObject = new JSONObject(strUserData);
                        if (line_dialog != null && lineListener != null && mHosterKit != null) {
                            lineListener.AddAudioGuest(new LineBean(strLivePeerID, jsonObject.getString("nickName"), false), mHosterKit);
                            tvLineList.setSelected(true);
                        }
                        applyLineList.add(strLivePeerID);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
        }


        /**
         * 游客挂断连线回调
         * @param strLivePeerID
         */
        @Override
        public void onRTCCancelLine(final int nCode, final String strLivePeerID) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCCancelLine  strLivePeerID:" + strLivePeerID + "nCode:" + nCode);

                    if (nCode == 602) {
                        ToastUtil.show("连麦人数已满");
                    }
                    if (nCode == 0) {
                        if (line_dialog != null && lineListener != null) {
                            lineListener.RemoveGuest(strLivePeerID);
                        }
                        if (applyLineList.contains(strLivePeerID)) {
                            applyLineList.remove(strLivePeerID);
                        }
                        if (applyLineList.size()==0){//小红点
                            tvLineList.setSelected(false);
                        }
                    }
                }
            });
        }


        @Override
        public void onRTCOpenRemoteVideoRender(String s, String s1, String s2, String s3) {

        }

        @Override
        public void onRTCCloseRemoteVideoRender(String s, String s1, String s2) {

        }

        @Override
        public void onRTCOpenRemoteAudioLine(final String strLivePeerId, final String strUserId, final String strUserData) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调: onRTCOpenRemoteAudioLine  strLivePeerID:" + strLivePeerId + " strUserId:" + strUserId + " strUserData:" + strUserData);
                    try {
                        JSONObject jsonObject = new JSONObject(strUserData);
                        audioLineAdapter.addData(new LineBean(strLivePeerId, jsonObject.getString("nickName"), false));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            });
        }

        @Override
        public void onRTCCloseRemoteAudioLine(final String strLivePeerId, final String strUserId) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调: onRTCCloseRemoteAudioLine  strLivePeerID:" + strLivePeerId + " strUserId:" + strUserId);
                    int index = 9;
                    for (int i = 0; i < audioLineAdapter.getData().size(); i++) {
                        if (audioLineAdapter.getItem(i).peerId.equals(strLivePeerId)) {
                            index = i;
                        }
                    }
                    if (index != 9 && index <= audioLineAdapter.getData().size()) {
                        audioLineAdapter.remove(index);
                    }

                }
            });
        }

        @Override
        public void onRTCLocalAudioActive(final int leave) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTLocalAudioActive leave:" + leave);
                }
            });
        }


        @Override
        public void onRTCRemoteAudioActive(final String strLivePeerId, final String strUserId, final int nTime) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCAudioActive  strLivePeerID:" + strLivePeerId + " strUserId:" + strUserId + " nTime:" + nTime);
                    if (strLivePeerId.equals("RTMPC_Hoster")) {//主播

                    } else {
//                        for (int i = 0; i < audioLineAdapter.getData().size(); i++) {
//                            if (strLivePeerId.equals(audioLineAdapter.getData().get(i).peerId)) {
//                                audioLineAdapter.getItem(i).setStartAnim(true);
//                                audioLineAdapter.notifyItemChanged(i);
//                            }
//                        }
                    }


                }
            });
        }

        @Override
        public void onRTCRemoteAVStatus(final String s, boolean b, boolean b1) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCRemoteAVStatus peerID:"+s);
                }
            });
        }

        /**
         * RTC 连接关闭回调
         * @param code 207:请去AnyRTC官网申请账号,如有疑问请联系客服!
         * @param strReason
         */
        /**
         * RTC 连接关闭回调
         * @param code 207:请去AnyRTC官网申请账号,如有疑问请联系客服!
         */
        @Override
        public void onRTCLineClosed(final int code, String s) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCLineClosedLine  code:" + code);
                }
            });
        }


        /**
         * 消息回调
         * @param strCustomID 消息的发送者id
         * @param strCustomName 消息的发送者昵称
         * @param strCustomHeader 消息的发送者头像url
         * @param strMessage 消息内容
         */
        @Override
        public void onRTCUserMessage(final int nType, final String strCustomID, final String strCustomName, final String strCustomHeader, final String strMessage) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCUserMessage  nType:" + nType + " strUserId:" + strCustomID + " strCustomName:" + strCustomName + " strCustomHeader:" + strCustomHeader + " strMessage:" + strMessage);
                    addChatMessageList(new MessageBean(MessageBean.AUDIO, strCustomName, strMessage));
                }
            });
        }

        /**
         * 观看直播的总人数回调
         * @param totalMembers 观看直播的总人数
         */
        @Override
        public void onRTCMemberNotify(final String strServerId, final String strRoomId, final int totalMembers) {
            AudioHosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCMemberNotify strServerId:" + strServerId + "strRoomId:" + strRoomId + "totalMembers:" + totalMembers);
                    tvMemberNum.setText("在线观看人数" + totalMembers + "");
                }
            });
        }


    };

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_close:
                ShowExitDialog();
                break;
            case R.id.iv_message:
                showChatLayout();
                break;
            case R.id.tv_line_list:
                if (isShowLineList) {
                    if (line_dialog != null) {
                        line_dialog.hide();
                        isShowLineList = false;
                    }
                } else {
                    if (line_dialog != null) {
                        line_dialog.show();
                        tvLineList.setSelected(false);
                        isShowLineList = true;
                    }
                }
                break;
            case R.id.btn_log:
                rl_log_layout.setVisibility(View.VISIBLE);
                break;
            case R.id.ibtn_close_log:
                rl_log_layout.setVisibility(View.GONE);
                break;
        }
    }

    private void initLineFragment() {
        CustomDialog.Builder builder = new CustomDialog.Builder(this);
        builder.setContentView(R.layout.item_line_list)
                .setAnimId(R.style.AnimBottom)
                .setGravity(Gravity.BOTTOM)
                .setLayoutParams(WindowManager.LayoutParams.MATCH_PARENT, DisplayUtils.getScreenHeightPixels(this) / 3)
                .setBackgroundDrawable(true)
                .build();
        line_dialog = builder.show(new CustomDialog.Builder.onInitListener() {
            @Override
            public void init(CustomDialog view) {
                if (lineFragment == null) {
                    lineFragment = new LineFragment();

                }
            }
        });
        line_dialog.hide();
        line_dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                isShowLineList = false;
            }
        });

    }

    public void SetLineListener(HosterActivity.LineListener mLineListener) {
        this.lineListener = mLineListener;
    }


    @Override
    public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
        if (mHosterKit != null) {
            mHosterKit.hangupRTCLine(audioLineAdapter.getItem(position).peerId);
            audioLineAdapter.remove(position);
        }

    }


}


================================================
FILE: app/src/main/java/org/ar/hoster/HosterActivity.java
================================================
package org.ar.hoster;

import android.content.DialogInterface;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import org.ar.BaseActivity;
import org.ar.ARApplication;
import org.ar.adapter.LiveMessageAdapter;
import org.ar.adapter.LogAdapter;
import org.ar.common.utils.ARAudioManager;
import org.ar.rtmpc.R;
import org.ar.model.LineBean;
import org.ar.model.MessageBean;
import org.ar.utils.ARUtils;
import org.ar.utils.DisplayUtils;
import org.ar.utils.ToastUtil;
import org.ar.widgets.ARVideoView;
import org.ar.widgets.CustomDialog;
import org.ar.widgets.KeyboardDialogFragment;
import org.ar.common.enums.ARVideoCommon;
import org.ar.rtmpc_hybrid.ARRtmpcEngine;
import org.ar.rtmpc_hybrid.ARRtmpcHosterEvent;
import org.ar.rtmpc_hybrid.ARRtmpcHosterKit;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.VideoRenderer;

import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


/**
 * 视频主播页面
 */
public class HosterActivity extends BaseActivity {
    RelativeLayout rlRtmpcVideos,rl_log_layout;
    TextView tvTitle,tvRtmpOk,tvRtmpStatus,tvRtcOk,tvMemberNum;
    RecyclerView rvMsgList,rvLog;
    View viewSpace;
    ImageButton tvLineList;
    private ARRtmpcHosterKit mHosterKit;
    private ARVideoView mVideoView;
    private ARAudioManager mRtmpAudioManager;
    private LiveMessageAdapter mAdapter;
    private LogAdapter logAdapter;
    private CustomDialog line_dialog;
    private LineFragment lineFragment;
    private boolean isShowLineList = false;
    private LineListener lineListener;

    private String pushURL = "",pullURL="";
    private String liveId= ARApplication.LIVE_ID;
    private String nickname= ARApplication.getNickName();
    private String userId="host"+(int)((Math.random()*9+1)*100000)+"";
    private List<String> applyLineList=new ArrayList<>();//申请连麦的人  这个用于判断小红点显示隐藏

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            ShowExitDialog();
        }
        return false;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();


        if (mHosterKit != null) {
            mVideoView.removeLocalVideoRender();
            mHosterKit.clean();
        }
        // Close RTMPAudioManager
        if (mRtmpAudioManager != null) {
            mRtmpAudioManager.stop();
            mRtmpAudioManager = null;
        }

    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_hoster;
    }

    @Override
    public void initView(Bundle savedInstanceState) {
        //设置屏幕常亮
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         rlRtmpcVideos=findViewById(R.id.rl_rtmpc_videos);
        rl_log_layout=findViewById(R.id.rl_log_layout);
        rvLog=findViewById(R.id.rv_log);
         tvTitle = findViewById(R.id.tv_title);
         tvRtmpOk = findViewById(R.id.tv_rtmp_ok);
         tvRtmpStatus = findViewById(R.id.tv_rtmp_status);
         tvRtcOk = findViewById(R.id.tv_rtc_ok);
         rvMsgList = findViewById(R.id.rv_msg_list);
         viewSpace=findViewById(R.id.view_space);
        mImmersionBar.titleBar(viewSpace).init();
         tvMemberNum=findViewById(R.id.tv_member_num);
         tvLineList=findViewById(R.id.tv_line_list);

        pushURL = getIntent().getStringExtra("pushURL");
        pullURL=getIntent().getStringExtra("pullURL");
        initLineFragment();
        mAdapter = new LiveMessageAdapter();
        rvMsgList.setLayoutManager(new LinearLayoutManager(this));
        rvMsgList.setAdapter(mAdapter);

        logAdapter = new LogAdapter();
        rvLog.setLayoutManager(new LinearLayoutManager(this));
        logAdapter.bindToRecyclerView(rvLog);

        //设置视频质量 参数对应清晰度,可查看API文档
        ARRtmpcEngine.Inst().getHosterOption().setVideoProfile(ARVideoCommon.ARVideoProfile.ARVideoProfile480x640);
        tvTitle.setText("房间ID:" + liveId);
        ARRtmpcEngine.Inst().getHosterOption().setVideoOrientation(ARVideoCommon.ARVideoOrientation.Portrait);
        //音频管理对象  当靠近听筒时将会减小音量
        mRtmpAudioManager = ARAudioManager.create(this);
        mRtmpAudioManager.start(new ARAudioManager.AudioManagerEvents() {
            @Override
            public void onAudioDeviceChanged(ARAudioManager.AudioDevice audioDevice, Set<ARAudioManager.AudioDevice> set) {

            }
        });
        ARRtmpcEngine.Inst().getHosterOption().setMediaType(ARVideoCommon.ARMediaType.Video);
        //实例化主播对象

        mHosterKit = new ARRtmpcHosterKit(mHosterListener);
        mHosterKit.setAudioActiveCheck(true);
        //实例化连麦窗口对象
        mVideoView = new ARVideoView(rlRtmpcVideos, ARRtmpcEngine.Inst().egl(), this,false,true);
        mVideoView.setVideoViewLayout(false,Gravity.RIGHT,LinearLayout.VERTICAL);
        mVideoView.setVideoLayoutOnclickEvent(mBtnVideoCloseEvent);
        //设置本地视频采集
        VideoRenderer render = mVideoView.openLocalVideoRender();
        mHosterKit.setLocalVideoCapturer(render.GetRenderPointer());
        //开始推流
        mHosterKit.startPushRtmpStream(pushURL);
        //创建RTC连接,必须放在开始推流之后
        mHosterKit.createRTCLine("", liveId, userId, getUserData(), getLiveInfo(pullURL,pullURL));
        //设置音频连麦直播,默认视频



        //=====================================视频数据相关===============================
//        /**
//         *  设置是否采用ARCamera,默认使用ARCamera, 如果设置为false,必须调用setByteBufferFrameCaptured才能本地显示
//         * @param usedARCamera true:使用ARCamera,false:不使用ARCamera采集的数据
//         */
//        mHosterKit.setUsedARCamera(true);
//        /**
//         * 设置本地显示的视频数据
//         * @param data 相机采集数据
//         * @param width 宽
//         * @param height 高
//         * @param rotation 旋转角度
//         * @param timeStamp 时间戳
//         */
//        mHosterKit.setByteBufferFrameCaptured();
       //设置ARCamera视频回调数据
//        mHosterKit.setARCameraCaptureObserver(new VideoCapturer.ARCameraCapturerObserver() {
//            @Override
//            public void onByteBufferFrameCaptured(byte[] data, int width, int height, int rotation, long timeStamp) {
//            }
//        });
        //=====================================视频数据相关===============================
    }

    public String getLiveInfo(String pullUrl,String hlsUrl) {
        JSONObject liveInfo = new JSONObject();

        try {
            liveInfo.put("hosterId", userId);
            liveInfo.put("rtmpUrl", pullUrl);
            liveInfo.put("hlsUrl", hlsUrl);
            liveInfo.put("liveTopic", ARApplication.LIVE_ID);
            liveInfo.put("anyrtcId", ARApplication.LIVE_ID);
            liveInfo.put("isAudioLive", 0);
            liveInfo.put("hosterName", ARApplication.getNickName());
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return liveInfo.toString();
    }

    public String getUserData() {
        JSONObject user = new JSONObject();
        try {
            user.put("isHost", 1);
            user.put("userId", userId);
            user.put("nickName", ARApplication.getNickName());
            user.put("headUrl", "www.baidu.com");

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return user.toString();
    }

    private void onAudioManagerChangedState() {
        // TODO(henrika): disable video if
        // AppRTCAudioManager.AudioDevice.EARPIECE
        // is active.
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
    }


    /**
     * 连线时小图标的关闭按钮
     */
    private ARVideoView.VideoLayoutOnclickEvent mBtnVideoCloseEvent = new ARVideoView.VideoLayoutOnclickEvent() {
        @Override
        public void onCloseVideoRender(View view, String strPeerId) {
            mHosterKit.hangupRTCLine(strPeerId);

        }
    };

    /**
     * 更细列表
     *
     * @param chatMessageBean
     */
    private void addChatMessageList(MessageBean chatMessageBean) {
        // 150 条 修改;

        if (chatMessageBean == null) {
            return;
        }

        if (mAdapter.getData().size() < 150) {
            mAdapter.addData(chatMessageBean);
        } else {
            mAdapter.remove(0);
            mAdapter.addData(chatMessageBean);
        }
        rvMsgList.smoothScrollToPosition(mAdapter.getData().size() - 1);
    }


    private void showChatLayout() {
        KeyboardDialogFragment keyboardDialogFragment = new KeyboardDialogFragment();
        keyboardDialogFragment.show(getSupportFragmentManager(), "KeyboardDialogFragment");
        keyboardDialogFragment.setEdittextListener(new KeyboardDialogFragment.EdittextListener() {
            @Override
            public void setTextStr(String text) {
                addChatMessageList(new MessageBean(MessageBean.VIDEO, nickname, text));
                mHosterKit.sendMessage(0, nickname, "", text);
            }

            @Override
            public void dismiss(DialogFragment dialogFragment) {
            }
        });
    }

    private void ShowExitDialog() {
        AlertDialog.Builder build = new AlertDialog.Builder(this);
        build.setTitle(R.string.str_exit);
        build.setMessage(R.string.str_live_stop);
        build.setPositiveButton(R.string.str_ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                if (mHosterKit != null) {
                    mHosterKit.stopRtmpStream();
                }
                finishAnimActivity();
            }
        });
        build.setNegativeButton(R.string.str_cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });

        build.show();
    }


    public void printLog(String log){
        Log.d("RTMPC", log);
        logAdapter.addData(log);
    }
    /**
     * 主播回调信息接口
     */
    private ARRtmpcHosterEvent mHosterListener = new ARRtmpcHosterEvent() {
        /**
         * rtmp连接成功
         */
        @Override
        public void onRtmpStreamOk() {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamOk");
                    if (tvRtmpOk != null) {
                        tvRtmpOk.setText("Rtmp连接成功");
                    }
                }
            });
        }

        /**
         * rtmp 重连次数
         * @param times 重连次数
         */
        @Override
        public void onRtmpStreamReconnecting(final int times) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamReconnecting times:" + times);
                    if (tvRtmpStatus != null) {
                        tvRtmpStatus.setText(String.format(getString(R.string.str_reconnect_times), times));
                    }
                }
            });
        }

        /**
         * rtmp 推流状态
         * @param delayMs 推流延时
         * @param netBand 推流码流
         */
        @Override
        public void onRtmpStreamStatus(final int delayMs, final int netBand) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamStatus delayMs:" + delayMs + "netBand:" + netBand);
                    if (tvRtmpStatus != null) {
                        tvRtmpStatus.setText(String.format(getString(R.string.str_rtmp_status), delayMs + "ms", netBand / 1024 / 8 + "kb/s"));
                    }
                }
            });
        }

        /**
         * rtmp推流失败回调
         * @param code
         */
        @Override
        public void onRtmpStreamFailed(final int code) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamFailed code:" + code);
                    if (tvRtcOk != null) {
                        tvRtcOk.setText(R.string.str_rtmp_connect_failed);
                    }
                }
            });
        }

        /**
         * rtmp 推流关闭回调
         */
        @Override
        public void onRtmpStreamClosed() {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRtmpStreamClosed ");
                    finish();
                }
            });

        }


        /**
         * RTC 连接回调
         * @param code 0: 连接成功
         */
        @Override
        public void onRTCCreateLineResult(final int code, String s) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调: onRTCCreateLineResult  code:" + code);
                    if (tvRtcOk != null) {
                        if (code == 0) {
                            tvRtcOk.setText(R.string.str_rtc_connect_success);
                        } else {
                            tvRtcOk.setText(ARUtils.getErrString(code));
                        }
                    }
                }
            });
        }


        /**
         * 游客有申请连线回调
         *
         * @param strLivePeerID
         * @param strCustomID
         * @param strUserData
         */
        @Override
        public void onRTCApplyToLine(final String strLivePeerID, final String strCustomID, final String strUserData) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCApplyToLine  strLivePeerID:" + strLivePeerID + " strCustomID:" + strCustomID + " strUserData:" + strUserData);
                    try {
                        String userdata = URLDecoder.decode(strUserData);
                        JSONObject jsonObject = new JSONObject(userdata);
                        if (line_dialog != null && lineListener != null && mHosterKit != null && tvLineList != null) {
                            lineListener.AddGuest(new LineBean(strLivePeerID, jsonObject.getString("nickName"), false), mHosterKit);
                            tvLineList.setSelected(true);
                        }
                        applyLineList.add(strLivePeerID);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            });
        }


        /**
         * 游客挂断连线回调
         * @param strLivePeerID
         */
        @Override
        public void onRTCCancelLine(final int nCode, final String strLivePeerID) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCCancelLine  strLivePeerID:" + strLivePeerID + "nCode:" + nCode);
                    if (nCode == 0) {
                        if (line_dialog != null && lineListener != null) {
                            lineListener.RemoveGuest(strLivePeerID);
                        }
                        if (applyLineList.contains(strLivePeerID)) {
                            applyLineList.remove(strLivePeerID);
                        }
                        if (applyLineList.size()==0){//小红点
                            tvLineList.setSelected(false);
                        }
                    }

                    if (nCode == 602) {
                        ToastUtil.show("连麦人数已满");
                    }
                }
            });
        }


        @Override
        public void onRTCOpenRemoteVideoRender(final String strLivePeerId, final String strPublishId, final String strUserId, final String strUserData) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCOpenVideoRender  strPublishId:" + strPublishId + " strUserId:" + strUserId + " strUserData:" + strUserData);
                    final VideoRenderer render = mVideoView.openRemoteVideoRender(strLivePeerId);
                    if (null != render) {
                        mHosterKit.setRTCRemoteVideoRender(strPublishId, render.GetRenderPointer());
                    }
                }
            });
        }

        @Override
        public void onRTCCloseRemoteVideoRender(final String strLivePeerId, final String strPublishId, final String strUserId) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCCloseVideoRender  strPublishId:" + strPublishId + " strUserId:" + strUserId);
                    mHosterKit.setRTCRemoteVideoRender(strPublishId, 0);
                    mVideoView.removeRemoteRender(strLivePeerId);
                    if (line_dialog != null && lineListener != null) {
                        lineListener.RemoveGuest(strLivePeerId);
                    }
                }
            });
        }

        @Override
        public void onRTCOpenRemoteAudioLine(String s, String s1, String s2) {

        }

        @Override
        public void onRTCCloseRemoteAudioLine(String s, String s1) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                }
            });
        }

        @Override
        public void onRTCLocalAudioActive(int i) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTLocalAudioActive ");
                }
            });
        }


        @Override
        public void onRTCRemoteAudioActive(String s, String s1, int i) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCRemoteAudioActive ");
                }
            });
        }

        @Override
        public void onRTCRemoteAVStatus(final String s, boolean b, boolean b1) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCRemoteAVStatus peerID:"+s);
                }
            });
        }


        /**
         * RTC 连接关闭回调
         * @param code 207:请去AnyRTC官网申请账号,如有疑问请联系客服!
         */
        @Override
        public void onRTCLineClosed(final int code, String s) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.d("RTMPC", "onRTCLineClosedLine  code:" + code);
                    if (code == 207) {
                        Toast.makeText(HosterActivity.this, getString(R.string.str_apply_anyrtc_account), Toast.LENGTH_LONG).show();
                        finish();
                    }
                }
            });
        }

        /**
         * 连线接通时的视频图像回调;
         */


        /**
         * 连线关闭时的视频图像回调;
         */


        /**
         * 消息回调
         * @param strCustomID 消息的发送者id
         * @param strCustomName 消息的发送者昵称
         * @param strCustomHeader 消息的发送者头像url
         * @param strMessage 消息内容
         */
        @Override
        public void onRTCUserMessage(final int nType, final String strCustomID, final String strCustomName, final String strCustomHeader, final String strMessage) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCUserMessage  nType:" + nType + " strUserId:" + strCustomID + " strCustomName:" + strCustomName + " strCustomHeader:" + strCustomHeader + " strMessage:" + strMessage);
                    addChatMessageList(new MessageBean(MessageBean.VIDEO, strCustomName, strMessage));
                }
            });
        }

        /**
         * 观看直播的总人数回调
         * @param totalMembers 观看直播的总人数
         */
        @Override
        public void onRTCMemberNotify(final String strServerId, final String strRoomId, final int totalMembers) {
            HosterActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    printLog("回调:onRTCMemberNotify strServerId:" + strServerId + "strRoomId:" + strRoomId + "totalMembers:" + totalMembers);
                    tvMemberNum.setText("在线人数:" + totalMembers + "");

                }
            });
        }

    };


    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_camare:
                if (mHosterKit == null) {
                    return;
                }
                mHosterKit.switchCamera();
                break;
            case R.id.btn_close:
                ShowExitDialog();
                break;
            case R.id.iv_message:
                showChatLayout();
                break;
            case R.id.tv_line_list:
                if (isShowLineList) {
                    if (line_dialog != null) {
                        line_dialog.hide();
                        isShowLineList = false;
                    }
                } else {
                    if (line_dialog != null) {
                        line_dialog.show();
                        tvLineList.setSelected(false);
                        isShowLineList = true;
                    }
                }
                break;
            case R.id.btn_log:
                rl_log_layout.setVisibility(View.VISIBLE);
                break;
            case R.id.ibtn_close_log:
                rl_log_layout.setVisibility(View.GONE);
                break;
        }
    }


    private void initLineFragment() {
        CustomDialog.Builder builder = new CustomDialog.Builder(this);
        builder.setContentView(R.layout.item_line_list)
                .setAnimId(R.style.AnimBottom)
                .setGravity(Gravity.BOTTOM)
                .setLayoutParams(WindowManager.LayoutParams.MATCH_PARENT, DisplayUtils.getScreenHeightPixels(this) / 3)
                .setBackgroundDrawable(true)
                .build();
        line_dialog = builder.show(new CustomDialog.Builder.onInitListener() {
            @Override
            public void init(CustomDialog view) {
                if (lineFragment == null) {
                    lineFragment = new LineFragment();
                }
            }
        });
        line_dialog.hide();
        line_dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                isShowLineList = false;
            }
        });

    }




    public interface LineListener {
        void AddAudioGuest(LineBean lineBean, ARRtmpcHosterKit hosterKit);//添加音频游客的申请到列表

        void AddGuest(LineBean lineBean, ARRtmpcHosterKit hosterKit);//添加游客的申请到列表

        void RemoveGuest(String peerid);//从列表移除游客
    }

    public void SetLineListener(LineListener mLineListener) {
        this.lineListener = mLineListener;
    }

    public void closeLineDialog() {
        if (line_dialog != null) {
            line_dialog.hide();
        }
    }

}


================================================
FILE: app/src/main/java/org/ar/hoster/LineFragment.java
================================================
package org.ar.hoster;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.chad.library.adapter.base.BaseQuickAdapter;

import org.ar.adapter.LiveLineAdapter;
import org.ar.rtmpc.R;
import org.ar.model.LineBean;
import org.ar.rtmpc_hybrid.ARRtmpcHosterKit;

/**
 * Created by liuxiaozhong on 2017/9/24.
 */

public class LineFragment extends Fragment implements HosterActivity.LineListener,BaseQuickAdapter.OnItemChildClickListener{

    private RecyclerView lineList;
    private LiveLineAdapter mAadapter;
    private ARRtmpcHosterKit rtmpcHosterKit;
    private ARRtmpcHosterKit audioHosterKit;
    private HosterActivity activity;
    private AudioHosterActivity audioHosterActivity;
    private SwipeRefreshLayout swipe_refresh;
    private boolean isAudioLive=false;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_line, container, false);
        swipe_refresh= (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh);
        swipe_refresh.setEnabled(false);
        lineList= (RecyclerView) view.findViewById(R.id.rv_list);
        lineList.setLayoutManager(new LinearLayoutManager(getActivity()));
        mAadapter=new LiveLineAdapter();
        mAadapter.setEmptyView(R.layout.empty_no_line_data, (ViewGroup) lineList.getParent());
        mAadapter.setOnItemChildClickListener(this);
        lineList.setAdapter(mAadapter);
        if (getActivity() instanceof HosterActivity){
            isAudioLive=false;
            activity= (HosterActivity) getActivity();
            activity.SetLineListener(this);
        }else {
            isAudioLive=true;
            audioHosterActivity= (AudioHosterActivity) getActivity();
            audioHosterActivity.SetLineListener(this);
        }


        return view;

    }

    @Override
    public void AddAudioGuest(LineBean lineBean, ARRtmpcHosterKit hosterKit) {
        isAudioLive=true;
        this.audioHosterKit=hosterKit;
        mAadapter.addData(lineBean);
    }

    @Override
    public void AddGuest(LineBean lineBean, ARRtmpcHosterKit hosterKit) {
        isAudioLive=false;
        this.rtmpcHosterKit=hosterKit;
        mAadapter.addData(lineBean);
    }

    @Override
    public void RemoveGuest(String peerid) {
        int index=9;
        for (int i=0;i<mAadapter.getData().size();i++){
            if (mAadapter.getItem(i).peerId.equals(peerid)){
                index=i;
            }
        }
        if (index!=9&&index<=mAadapter.getData().size()){
            mAadapter.remove(index);
        }
    }


    @Override
    public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
        switch (view.getId()){
            case R.id.tv_agree:
                if (isAudioLive){
                    if (audioHosterKit != null) {
                        audioHosterKit.acceptRTCLine(mAadapter.getItem(position).peerId);
                        mAadapter.remove(position);

                    }
                }else {
                    if (rtmpcHosterKit != null) {
                        rtmpcHosterKit.acceptRTCLine(mAadapter.getItem(position).peerId);
                        mAadapter.remove(position);
                            if (activity != null) {
                                activity.closeLineDialog();
                        }
                    }
                }

                break;
            case R.id.tv_refuse:
                if (isAudioLive){
                    if (audioHosterKit != null) {
                        audioHosterKit.rejectRTCLine(mAadapter.getItem(position).peerId);
                        mAadapter.remove(position);
                    }
                }else {
                    if (rtmpcHosterKit != null) {
                        rtmpcHosterKit.rejectRTCLine(mAadapter.getItem(position).peerId);
                        mAadapter.remove(position);
                    }
                }
                break;
        }
    }

    public LiveLineAdapter getmAadapter() {
        return mAadapter;
    }
}


================================================
FILE: app/src/main/java/org/ar/model/LineBean.java
================================================
package org.ar.model;

/**
 * Created by liuxiaozhong on 2017/9/24.
 */

public class LineBean {
    public String peerId;
    public String name;
    public boolean isSelf;
    public boolean startAnim;

    public LineBean(String peerId, String name,boolean isSelf) {
        this.peerId = peerId;
        this.name = name;
        this.isSelf=isSelf;
    }

    public boolean isStartAnim() {
        return startAnim;
    }

    public void setStartAnim(boolean startAnim) {
        this.startAnim = startAnim;
    }

    public boolean isSelf() {
        return isSelf;
    }

    public void setSelf(boolean self) {
        isSelf = self;
    }
}


================================================
FILE: app/src/main/java/org/ar/model/LiveBean.java
================================================
package org.ar.model;

import java.io.Serializable;

/**
 * Created by liuxiaozhong on 2017-09-22.
 */

public class LiveBean implements Serializable{

    public String mRtmpPullUrl;
    public String mHlsUrl;
    public String mPushUrl;
    public String mLiveTopic;
    public String mAnyrtcId;
    public int isAudioLive;
    public int isLiveLandscape;
    public int liveMode;
    public String mHostName;
    public String mMemberNum="";

    public String getmRtmpPullUrl() {
        return mRtmpPullUrl;
    }

    public void setmRtmpPullUrl(String mRtmpPullUrl) {
        this.mRtmpPullUrl = mRtmpPullUrl;
    }

    public String getmHlsUrl() {
        return mHlsUrl;
    }

    public void setmHlsUrl(String mHlsUrl) {
        this.mHlsUrl = mHlsUrl;
    }

    public String getmPushUrl() {
        return mPushUrl;
    }

    public void setmPushUrl(String mPushUrl) {
        this.mPushUrl = mPushUrl;
    }

    public String getmLiveTopic() {
        return mLiveTopic;
    }

    public void setmLiveTopic(String mLiveTopic) {
        this.mLiveTopic = mLiveTopic;
    }

    public String getmAnyrtcId() {
        return mAnyrtcId;
    }

    public void setmAnyrtcId(String mAnyrtcId) {
        this.mAnyrtcId = mAnyrtcId;
    }

    public int getIsAudioLive() {
        return isAudioLive;
    }

    public void setIsAudioLive(int isAudioLive) {
        this.isAudioLive = isAudioLive;
    }

    public int getIsLiveLandscape() {
        return isLiveLandscape;
    }

    public void setIsLiveLandscape(int isLiveLandscape) {
        this.isLiveLandscape = isLiveLandscape;
    }

    public int getLiveMode() {
        return liveMode;
    }

    public void setLiveMode(int liveMode) {
        this.liveMode = liveMode;
    }

    public String getmHostName() {
        return mHostName;
    }

    public void setmHostName(String mHostName) {
        this.mHostName = mHostName;
    }

    public String getmMemberNum() {
        return mMemberNum;
    }

    public void setmMemberNum(String mMemberNum) {
        this.mMemberNum = mMemberNum;
    }
}


================================================
FILE: app/src/main/java/org/ar/model/MessageBean.java
================================================
package org.ar.model;

/**
 * Created by liuxiaozhong on 2017-09-22.
 */

public class MessageBean {
    public final static int VIDEO = 1;
    public final static int AUDIO = 0
            ;
    public int type;//0 video 1 audio
    public String name;
    public String content;

    public MessageBean(int type, String name, String content) {
        this.type = type;
        this.name = name;
        this.content = content;
    }
}


================================================
FILE: app/src/main/java/org/ar/utils/ARUtils.java
================================================
package org.ar.utils;

import org.ar.ARApplication;
import org.ar.rtmpc.R;

/**
 * Created by Skyline on 2016/11/1.
 */

public enum ARUtils {
    AnyRTC_OK(0),               // 正常
    AnyRTC_UNKNOW(1),           // 未知错误
    AnyRTC_EXCEPTION(2),	    // SDK调用异常


    AnyRTC_NET_ERR(100),		// 网络错误
    AnyRTC_NET_DISSCONNECT(101),	// 网络断开
    AnyRTC_LIVE_ERR(101),		// 直播出错



    AnyRTC_BAD_REQ(201),		// 服务不支持的错误请求
    AnyRTC_AUTH_FAIL(202),		// 认证失败
    AnyRTC_NO_USER(203),		// 此开发者信息不存在
    AnyRTC_SQL_ERR(204),		// 服务器内部数据库错误
    AnyRTC_ARREARS(205),		// 账号欠费
    AnyRTC_LOCKED(206),		    // 账号被锁定
    AnyRTC_FORCE_EXIT(207),    // 强制离开
    AnyRTC_ID_INVALIDE(208),	// AnyRTC ID非法(仅会议和RTCP中检测)
    AnyRTC_SERVICE_CLOSED (209),// 服务未开通
    AnyRTC_BUNDLE_ID_ERR (210),	// Bundle ID不匹配
    AnyRTC_PUB_GONE (211),		// 订阅的PubID已过期
    AnyRTC_NO_RTC_SVR(212);	// 没有RTC服务器

    private int value;

    ARUtils(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    /**
     * 根据错误码获取文字描述
     * @param value
     * @return
     */
    public static String getErrString(int value) {
        if (value == AnyRTC_OK.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_ok);
        } else if (value == AnyRTC_UNKNOW.getValue()) {
            return ARApplication.App().getString(R.string.str_unknow_exception);
        } else if (value == AnyRTC_EXCEPTION.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_exception);
        } else if (value == AnyRTC_NET_ERR.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_net_err);
        } else if (value == AnyRTC_LIVE_ERR.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_live_err);
        } else if (value == AnyRTC_BAD_REQ.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_bad_req);
        } else if (value == AnyRTC_AUTH_FAIL.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_auth_fail);
        } else if (value == AnyRTC_NO_USER.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_no_user);
        } else if (value == AnyRTC_SQL_ERR.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_sql_err);
        } else if (value == AnyRTC_ARREARS.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_arrears);
        } else if (value == AnyRTC_LOCKED.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_locked);
        } else if (value == AnyRTC_FORCE_EXIT.getValue()) {
            return ARApplication.App().getString(R.string.str_anyrtc_force_exit);
        } else {
            return "";
        }
    }
}


================================================
FILE: app/src/main/java/org/ar/utils/DisplayUtils.java
================================================
package org.ar.utils;

import android.app.Activity;
import android.content.Context;
import android.util.DisplayMetrics;

public class DisplayUtils {
	/**
	 * 将px值转换为dp值
	 */
	public static int px2dp(Context context, float pxValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (pxValue / scale + 0.5f);
	}

	/**
	 * 将dp值转换为px值
	 */
	public static int dp2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

	/**
	 * 将px值转换为sp值
	 */
	public static int px2sp(Context context, float pxValue) {
		final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
		return (int) (pxValue / fontScale + 0.5f);
	}

	/**
	 * 将sp值转换为px值
	 */
	public static int sp2px(Context context, float spValue) {
		final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
		return (int) (spValue * fontScale + 0.5f);
	}

	/**
	 * 获取屏幕宽度
	 */
	public static int getScreenWidthPixels(Activity context) {
		DisplayMetrics metric = new DisplayMetrics();
		context.getWindowManager().getDefaultDisplay().getMetrics(metric);
		return metric.widthPixels;
	}

	/**
	 * 获取屏幕高度
	 */
	public static int getScreenHeightPixels(Activity context) {
		DisplayMetrics metric = new DisplayMetrics();
		context.getWindowManager().getDefaultDisplay().getMetrics(metric);
		return metric.heightPixels;
	}


}


================================================
FILE: app/src/main/java/org/ar/utils/MD5.java
================================================
package org.ar.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by liuxiaozhong on 2016/5/30.
 */
public class MD5 {

    public static String getMD5(String password ) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(password.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if(i<0) i+= 256;
                if(i<16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            return buf.toString().toLowerCase();
            //System.out.println("result: " + buf.toString());//32位的加密
           // System.out.println("result: " + buf.toString().substring(8,24));//16位的加密
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }


}


================================================
FILE: app/src/main/java/org/ar/utils/NameUtils.java
================================================
package org.ar.utils;

import java.util.Random;

/**
 * Created by Skyline on 2016/8/8.
 */
public class NameUtils {
    public static String[] userNickname = new String[]{"John", "Michelle", "Amy", "Kim", "Mary", "David", "Sunny", "James", "Maria", "Michael", "Sarah", "Robert", "Lily"
            , "William", "Jessica", "Paul", "Crystal", "Peter", "Jennifer", "George", "Rachel", "Thomas", "Lisa", "Daniel", "Elizabeth"
            , "Kevin", "Angela", "Richard", "Emily", "Charles", "Eva", "Jason", "Jenny", "Mark", "Alice", "Eric", "Candy", "Chris", "Linda"
            , "Jack", "Tina", "Alex", "Sara", "Edward", "Emma", "Tony", "Anne", "Joseph", "Cindy", "Henry", "Grace", "Alan", "Susan", "Anna"
            , "Maggie", "Christian", "Annie", "Tom", "Rebecca", "Andy", "Claire", "Carlos", "Vanessa", "Steven", "Judy", "Stephen", "Catherine"
            , "Jean", "Helen", "Andrew", "Christina", "Jonathan", "Karen", "Frank", "Marco", "Elaine", "Gary", "Nana", "Antonio", "Nicole"
            , "Alexander", "Margaret", "Matthew", "Julia", "Louis", "Lucy", "Jose", "Natalie", "Martin", "Kate", "Patrick", "Olivia", "Sam"
            , "Betty", "Angel", "Laura", "Anthony", "Ellen", "Luis", "Elena", "Leo", "Samuel", "Vicky", "Brian", "Summer", "Sean", "Nancy"
            , "Carl", "Zoe", "Diego", "Teresa", "Danny", "Wendy", "Jerry", "Christine", "Karl", "Princess", "Nick", "Barbara", "Albert"
            , "Julie", "Ryan", "Amber", "Johnny", "Stephanie", "Mike", "Sharon", "Aaron", "Sophia", "Kelly", "Yvonne", "Tim", "Tiffany"
            , "Roberto", "Marie", "Alfred", "Simon", "Lauren", "Andrea", "Gina", "Diana", "Mario", "Doris", "Victor", "Fiona", "Ivan"
            , "Victoria", "Fernando", "Caroline", "Adam", "Ivy", "Miguel", "Alexandra", "Raymond", "Jessie", "Ray", "Lulu", "Arthur"
            , "Janet", "Ricardo", "King", "Cynthia", "Vincent", "Cherry", "Jeremy", "Bonnie", "Andre", "Isabella", "Christopher", "Kitty"
            , "Dennis", "Mia", "Harry", "Rose", "Leon", "Cecilia", "Jacky", "Louise", "Bob", "Rita", "Bill", "Katie", "Sebastian", "Erica"
            , "Oscar", "Jacqueline", "Philip", "Ruby", "Benjamin", "Miranda", "Jim", "Iris", "Jeff", "Queen", "Scott", "Esther", "Kenneth"
            , "Melissa", "Justin", "Nathan"};

    public static String getNickName() {
        return userNickname[new Random().nextInt(200)];
    }
}


================================================
FILE: app/src/main/java/org/ar/utils/PermissionsCheckUtil.java
================================================
package org.ar.utils;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;

public class PermissionsCheckUtil {

    public static final int SETTING_APP = 0x123;
    private static String TAG = "PermissionsCheckUtil";
    private static String[] PHONE_MTYB = new String[]{"sanxing", "xiaomi"};

    /**
     * @param activity
     * @param message  显示缺失权限提示说明
     */
    public static void showMissingPermissionDialog(final Activity activity, String message) {
        boolean canSetting = false;
        String mtyb = Build.BRAND;//手机品牌
        for (int i = 0; i < PHONE_MTYB.length; i++) {
            if (PHONE_MTYB[i].equalsIgnoreCase(mtyb)) {//相等可以调用到设置界面进行权限设置
                canSetting = true;
                break;
            } else {
                canSetting = false;
            }
        }
        final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setTitle("帮助");
        builder.setMessage(message);
        if (canSetting) {
            builder.setPositiveButton("设置", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    startAppSettings(activity);
                    dialog.dismiss();
                }
            });
        }
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.show();
    }

    // 启动应用的设置
    public static void startAppSettings(Activity activity) {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + activity.getPackageName()));
        activity.startActivityForResult(intent, SETTING_APP);
    }
}


================================================
FILE: app/src/main/java/org/ar/utils/ScreenUtils.java
================================================
package org.ar.utils;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.WindowManager;

/**
 * Get screen associated auxiliary class
 *
 * @author Ming <br/>
 */
public class ScreenUtils {
    private ScreenUtils() {
        /* cannot be instantiated */
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * dip to px
     *
     * @param dip
     * @param context
     * @return
     */
    public static float dip2Dimension(float dip, Context context) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
    }

    public static int dpToP(Resources paramResources, int paramInt) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paramInt,
                paramResources.getDisplayMetrics());
    }

    /**
     * @param context
     * @param complexUnit {@link TypedValue#COMPLEX_UNIT_DIP}
     *                    {@link TypedValue#COMPLEX_UNIT_SP}
     * @return
     */
    public static float toDimension(float dip, Context context, int complexUnit) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return TypedValue.applyDimension(complexUnit, dip, displayMetrics);
    }

    /**
     * Get screen width
     *
     * @param context
     * @return
     */
    public static int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);

        return outMetrics.widthPixels;
    }

    /**
     * Get screen height
     *
     * @param context
     * @return
     */
    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }


    /**
     * 判断是否为平板
     *
     * @return
     */
    public static boolean isPad(Context context) {

        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        int width = dm.widthPixels;
        int height = dm.heightPixels;
        double x = Math.pow(width, 2);
        double y = Math.pow(height, 2);
        double diagonal = Math.sqrt(x + y);

        int dens = dm.densityDpi;
        double screenInches = diagonal / (double) dens;
        // 大于6尺寸则为Pad
        if (screenInches >= 6.0) {
            return true;
        }
        return false;

    }

    /**
     * 获得状态栏的高度
     *
     * @param context
     * @return
     */
    public static int getStatusHeight(Context context) {

        int statusHeight = -1;
        try {
            Class<?> clazz = Class.forName("com.android.internal.R$dimen");
            Object object = clazz.newInstance();
            int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
            statusHeight = context.getResources().getDimensionPixelSize(height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return statusHeight;
    }

    /**
     * 获取当前屏幕截图,包含状态栏
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithStatusBar(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
        view.destroyDrawingCache();
        return bp;

    }

    /**
     * 获取当前屏幕截图,不包含状态栏
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithoutStatusBar(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        Rect frame = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;

        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);
        view.destroyDrawingCache();
        return bp;

    }

    public static final int getHeightInPx(Context context) {
        final int height = context.getResources().getDisplayMetrics().heightPixels;
        return height;
    }

    public static final int getWidthInPx(Context context) {
        final int width = context.getResources().getDisplayMetrics().widthPixels;
        return width;
    }

    public static final int getHeightInDp(Context context) {
        final float height = context.getResources().getDisplayMetrics().heightPixels;
        int heightInDp = px2dip(context, height);
        return heightInDp;
    }

    public static final int getWidthInDp(Context context) {
        final float height = context.getResources().getDisplayMetrics().heightPixels;
        int widthInDp = px2dip(context, height);
        return widthInDp;
    }

    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    public static int px2sp(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    public static int sp2px(Context context, float spValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (spValue * scale + 0.5f);
    }


}


================================================
FILE: app/src/main/java/org/ar/utils/ToastUtil.java
================================================
package org.ar.utils;


import android.content.Context;
import android.text.TextUtils;
import android.view.Gravity;
import android.widget.Toast;

import org.ar.ARApplication;

/**
 * Created by Skyline on 2016/5/24.
 */
public class ToastUtil {
    private static Context context = ARApplication.App();
    private static Toast mToast;

    public static void show(int resId) {
        show(context.getResources().getText(resId), Toast.LENGTH_SHORT);
    }

    public static void show(int resId, int duration) {
        show(context.getResources().getText(resId), duration);
    }

    public static void show(CharSequence text) {
        show(text, Toast.LENGTH_SHORT);
    }

    public static void show(CharSequence text, int duration) {
        text = TextUtils.isEmpty(text == null ? "" : text.toString()) ? ""
                : text;
        if (mToast == null) {
            mToast = Toast.makeText(context, text, duration);
            mToast.setGravity(Gravity.CENTER, 0, 0);
        } else {
            mToast.setText(text);
        }
        mToast.show();
    }

    public static void show(int resId, Object... args) {
        show(String.format(context.getResources().getString(resId), args),
                Toast.LENGTH_SHORT);
    }

    public static void show(String format, Object... args) {
        show(String.format(format, args), Toast.LENGTH_SHORT);
    }

    public static void show(int resId, int duration, Object... args) {
        show(String.format(context.getResources().getString(resId), args),
                duration);
    }

    public static void show(String format, int duration, Object... args) {
        show(String.format(format, args), duration);
    }

    public void cancelToast() {
        if (mToast != null) {
            mToast.cancel();
        }
    }
}


================================================
FILE: app/src/main/java/org/ar/widgets/ARVideoView.java
================================================
package org.ar.widgets;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import org.ar.common.utils.ScreenUtils;
import org.ar.rtmpc.R;
import org.webrtc.EglBase;
import org.webrtc.EglRenderer;
import org.webrtc.PercentFrameLayout;
import org.webrtc.RendererCommon;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoRenderer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static android.view.View.VISIBLE;

/**
 * Created by liuxiaozhong on 2019/1/11.
 */
public class ARVideoView implements View.OnTouchListener{

    public RelativeLayout rlVideoGroup;//所有视频的容器布局

    private EglBase eglBase;//底层视频渲染相关对象

    private Context mContext;//上下文对象

    private VideoView LocalVideoRender;//本地视频显示对象

    private LinkedHashMap<String, VideoView> mRemoteRenderList;//远程视频集合

    private static int mScreenWidth;//屏幕宽

    private static int mScreenHeight;//屏幕高

    private boolean isSameSize=false;//是否是平均大小模式
    private boolean is169 = false;//比例是否是16:9
    private int direction = Gravity.CENTER;//1大几小的时候  小像位置
    private int orientation = LinearLayout.HORIZONTAL;//1大几小的时候  小像横向或纵向排列

    private static int SUB_WIDTH = 0;
    private static int SUB_HEIGHT = 0;

    private boolean isHost ;//是否是主播

    VideoLayoutOnclickEvent videoLayoutOnclickEvent;

    public interface VideoLayoutOnclickEvent {
        void onCloseVideoRender(View view, String strPeerId);

    }

    public void setVideoLayoutOnclickEvent(VideoLayoutOnclickEvent videoLayoutOnclickEvent) {
        this.videoLayoutOnclickEvent = videoLayoutOnclickEvent;
    }

    public ARVideoView(RelativeLayout rlVideoGroup, EglBase eglBase, Context context, boolean isSameSize, boolean isHost) {

        this.rlVideoGroup = rlVideoGroup;
        this.eglBase = eglBase;
        this.mContext = context;
        this.isSameSize=isSameSize;
        this.isHost=isHost;
        mRemoteRenderList = new LinkedHashMap<>();
        mScreenWidth = ScreenUtils.getScreenWidth(mContext);
        mScreenHeight = ScreenUtils.getScreenHeight(mContext) - ScreenUtils.getStatusHeight(mContext);
    }

    public void setVideoSwitchEnable(boolean enable) {
        if (!isSameSize) {
            rlVideoGroup.setOnTouchListener(this);
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            int startX = (int) event.getX();
            int startY = (int) event.getY();
            if (LocalVideoRender.Hited(startX, startY)) {
                return true;
            } else {
                Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry<String, VideoView> entry = iter.next();
                    String peerId = entry.getKey();
                    VideoView render = entry.getValue();
                    if (render.Hited(startX, startY)) {
                        return true;
                    }
                }
            }
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            int startX = (int) event.getX();
            int startY = (int) event.getY();
            if (LocalVideoRender.Hited(startX, startY)) {
                SwitchViewToFullscreen(LocalVideoRender, GetFullScreen());
                return true;
            } else {
                Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry<String, VideoView> entry = iter.next();
                    String peerId = entry.getKey();
                    VideoView render = entry.getValue();
                    if (render.Hited(startX, startY)) {
                        SwitchViewToFullscreen(render, GetFullScreen());
                        return true;
                    }
                }
            }
        }
        return false;
    }


    /**
     * 一个VideoView对象 就是一个视频渲染对象 里面的方法 UI 可以根据需求自定义
     */
    protected static class VideoView {
        public String videoId; //视频ID 保持唯一
        public int index; //视频的下标
        public int x; //装载视频的容器的起始X轴位置  最大100 最左边为0
        public int y; //装载视频的容器的起始Y轴位置  最大100 最上边为0
        public int w; //装载视频的容器的宽  最大100
        public int h; //装载视频的容器的高  最大100
        public PercentFrameLayout mLayout = null;//自定义宽高为百分比的布局控件
        public SurfaceViewRenderer surfaceViewRenderer = null; //显示视频的SurfaceView
        private FrameLayout flLoading; //视频显示前的Loading
        public VideoRenderer videoRenderer = null; //底层视频渲染对象
        public ImageButton btnHangUp;

        public VideoView(String videoId, Context ctx, EglBase eglBase, int index, int x, int y, int w, int h) {
            this.videoId = videoId;
            this.index = index;
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;

            mLayout = new PercentFrameLayout(ctx);
            mLayout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
            View view = View.inflate(ctx, R.layout.layout_arvideo, null);//这个View可完全自定义 需要显示名字或者其他图标可以在里面加
            flLoading = (FrameLayout) view.findViewById(R.id.fl_video_loading);
            btnHangUp=view.findViewById(R.id.ibtn_hang_up);
            surfaceViewRenderer = (SurfaceViewRenderer) view.findViewById(R.id.sv_video_render);
            surfaceViewRenderer.init(eglBase.getEglBaseContext(), null);
            surfaceViewRenderer.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
            mLayout.addView(view);//将SurfaceView添加到自定义宽高为百分比的布局控件中
        }

        /**
         * 该视频对象是否全屏显示
         *
         * @return true false
         */
        public Boolean isFullScreen() {
            return w == 100 || h == 100;
        }

        /**
         * 是否点击了该视频对象
         *
         * @param px
         * @param py
         * @return
         */
        public Boolean Hited(int px, int py) {
            if (!isFullScreen()) {
                int left = x * mScreenWidth / 100;
                int top = y * mScreenHeight / 100;
                int right = (x + w) * mScreenWidth / 100;
                int bottom = (y + h) * mScreenHeight / 100;
                if ((px >= left && px <= right) && (py >= top && py <= bottom)) {
                    return true;
                }
            }
            return false;
        }

        public void close() {
            mLayout.removeView(surfaceViewRenderer);
            surfaceViewRenderer.release();
            surfaceViewRenderer = null;
            videoRenderer = null;
        }

    }


    /**
     * 仅用于1大几小
     * 1个大像和几个小像的时候设置
     * @param is169  比例是否是16:9  true 16:9  false 4:3
     * @param direction 显示位置 左边 中间  右边
     * @param orientation 排列方式 垂直 横向
     */
    public void setVideoViewLayout(boolean is169, int direction, int orientation) {
        this.is169 = is169;
        this.direction = direction;
        this.orientation = orientation;
        if (!isSameSize) {
            changeSizeWhenRotate(false);
        }
    }

    /**
     * 仅用于1大几小
     * 旋转屏幕时改变尺寸
     * isFirst 是否是第一次  是的话 是不需要更新视频View的
     */
    public void changeSizeWhenRotate(boolean isFirst) {
        if (is169) {
            if (mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {//横屏
                SUB_WIDTH = (int) (((mScreenWidth / 5f) * 1.777777f) / (mScreenHeight / 100f));
                SUB_HEIGHT=(int) ((mScreenWidth / 5f) / (mScreenWidth / 100f));
            } else {
                SUB_HEIGHT = (int) (((mScreenWidth / 5f) * 1.777777f) / (mScreenHeight / 100f));
                SUB_WIDTH = (int) ((mScreenWidth / 5f) / (mScreenWidth / 100f));
            }
        } else {
            if (mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {//横屏
                SUB_WIDTH = (int) (((mScreenWidth / 4f) * 1.33333f) / (mScreenHeight / 100f));
                SUB_HEIGHT=(int) ((mScreenWidth / 4f) / (mScreenWidth / 100f));
            } else {
                SUB_HEIGHT = (int) (((mScreenWidth / 3f) /1.33333f) / (mScreenHeight / 100f));
                SUB_WIDTH = (int) ((mScreenWidth / 3f) / (mScreenWidth / 100f));
            }
        }
        if (!isFirst){
            updateVideoView1Big();
        }

    }




    /**
     * 获取视频窗口的个数
     *
     * @return
     */
    public int getVideoRenderSize() {
        int size = mRemoteRenderList.size();
        if (LocalVideoRender != null) {
            size += 1;
        }
        return size;
    }


    /**
     * 打开本地摄像头渲染对象
     *
     * @return
     */
    public VideoRenderer openLocalVideoRender() {
        int size = getVideoRenderSize();
        if (size == 0) {
            LocalVideoRender = new VideoView("localRender", rlVideoGroup.getContext(), eglBase, 0, 0, 0, 100, 100);
            LocalVideoRender.surfaceViewRenderer.setZOrderMediaOverlay(false);
        } else {
            LocalVideoRender = new VideoView("localRender", rlVideoGroup.getContext(), eglBase, size, 0, 0, 100, 100);
            LocalVideoRender.surfaceViewRenderer.setZOrderMediaOverlay(false);
        }
        rlVideoGroup.addView(LocalVideoRender.mLayout, -1);
        LocalVideoRender.mLayout.setPosition(
                LocalVideoRender.x, LocalVideoRender.y, LocalVideoRender.w, LocalVideoRender.h);
        LocalVideoRender.surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        LocalVideoRender.flLoading.setVisibility(VISIBLE);
        LocalVideoRender.surfaceViewRenderer.addFrameListener(new EglRenderer.FrameListener() {
            @Override
            public void onFrame(Bitmap frame) {
                Log.d("surfaceView", frame.toString());
                LocalVideoRender.surfaceViewRenderer.post(new Runnable() {
                    @Override
                    public void run() {
                        LocalVideoRender.flLoading.setVisibility(View.GONE);
                    }
                });

            }
        }, 1f);
        if (isSameSize){
            updateVideoViewSameSize();
        }else {
            updateVideoView1Big();
        }
        LocalVideoRender.videoRenderer = new VideoRenderer(LocalVideoRender.surfaceViewRenderer);
        return LocalVideoRender.videoRenderer;
    }

    /**
     * 移除本地视频渲染对象
     */
    public void removeLocalVideoRender() {
        if (LocalVideoRender != null) {
            LocalVideoRender.close();
            LocalVideoRender.videoRenderer = null;
            rlVideoGroup.removeView(LocalVideoRender.mLayout);
            LocalVideoRender = null;
            if (isSameSize){
                updateVideoViewSameSize();
            }else {
                updateVideoView1Big();
            }
        }
    }


    /**
     * 打开远程视频渲染对象
     *
     * @param videoId 视频ID
     * @return
     */
    public VideoRenderer openRemoteVideoRender(final String videoId) {
        VideoView remoteVideoRender = mRemoteRenderList.get(videoId);
        if (remoteVideoRender == null) {
            int size = getVideoRenderSize();
            if (size == 0) {
                remoteVideoRender = new VideoView(videoId, rlVideoGroup.getContext(), eglBase, 0, 0, 0, 100, 100);
            } else {
                remoteVideoRender = new VideoView(videoId, rlVideoGroup.getContext(), eglBase, size, 0, 0, 0, 0);
                remoteVideoRender.surfaceViewRenderer.setZOrderMediaOverlay(true);
            }
            rlVideoGroup.addView(remoteVideoRender.mLayout, -1);
            remoteVideoRender.mLayout.setPosition(
                    remoteVideoRender.x, remoteVideoRender.y, remoteVideoRender.w, remoteVideoRender.h);
            remoteVideoRender.surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
            remoteVideoRender.flLoading.setVisibility(VISIBLE);
            final VideoView finalRemoteVideoRender = remoteVideoRender;
            remoteVideoRender.surfaceViewRenderer.addFrameListener(new EglRenderer.FrameListener() {
                @Override
                public void onFrame(Bitmap frame) {
                    finalRemoteVideoRender.surfaceViewRenderer.post(new Runnable() {
                        @Override
                        public void run() {
                            finalRemoteVideoRender.flLoading.setVisibility(View.GONE);
                        }
                    });
                }
            }, 1f);
            remoteVideoRender.videoRenderer = new VideoRenderer(remoteVideoRender.surfaceViewRenderer);
            mRemoteRenderList.put(videoId, remoteVideoRender);
            if (isSameSize){
                updateVideoViewSameSize();
            }else {
                updateVideoView1Big();
            }
            if (isHost || (!isHost && videoId.equals("LocalCameraRender"))) {
                remoteVideoRender.btnHangUp.setVisibility(View.VISIBLE);
                remoteVideoRender.btnHangUp.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (null != videoLayoutOnclickEvent) {
                            videoLayoutOnclickEvent.onCloseVideoRender(v, videoId);
                        }
                    }
                });
            }
        }
        return remoteVideoRender.videoRenderer;
    }

    /**
     * 移除远程像
     *
     * @param videoId
     */
    public void removeRemoteRender(String videoId) {
        VideoView remoteVideoRender = mRemoteRenderList.get(videoId);
        if (remoteVideoRender != null) {
            remoteVideoRender.close();
            rlVideoGroup.removeView(remoteVideoRender.mLayout);
            mRemoteRenderList.remove(videoId);
            sortVideoRenderIndex();
            if (isSameSize){
                updateVideoViewSameSize();
            }else {
                updateVideoView1Big();
            }
        }
    }

    public void sortVideoRenderIndex() {
        List<Map.Entry<String, VideoView>> list = new ArrayList<Map.Entry<String, VideoView>>(mRemoteRenderList.entrySet());
        for (int i = 0; i < list.size(); i++) {
            list.get(i).getValue().index = i + 1;
        }
    }


    //第一种 1个大 多个小 小像从中间位置开始 最多5个

    /**
     * 1个大像 5个小像示例
     * 小像横排/竖排排列
     * 小像从左边 中间 右边开始排列
     */
    private void updateVideoView1Big() {
        int size = mRemoteRenderList.size();
        if (size == 0) {
            if (LocalVideoRender != null) {
                LocalVideoRender.x = 0;
                LocalVideoRender.y = 0;
                LocalVideoRender.w = 100;
                LocalVideoRender.h = 100;
                LocalVideoRender.mLayout.setPosition(0, 0, 100, 100);
                LocalVideoRender.surfaceViewRenderer.requestLayout();
            }
        } else {
            int startX = 0;
            int startY = 100-SUB_HEIGHT-2;
            if (orientation== LinearLayout.HORIZONTAL){
                if (direction == Gravity.CENTER) {
                    startX = (100 - (SUB_WIDTH * size)) / 2;//小像起始位置
                } else if (direction == Gravity.LEFT) {
                    startX = 0;
                } else if (direction == Gravity.RIGHT) {
                    startX = 100 - SUB_WIDTH;
                } else {
                    startX = (100 - (SUB_WIDTH * size)) / 2;
                }
            }else {
                if (direction == Gravity.CENTER) {
                    startX = (100 - SUB_WIDTH) / 2;//小像起始位置
                } else if (direction == Gravity.LEFT) {
                    startX = 0;
                } else if (direction == Gravity.RIGHT) {
                    startX = 100 - SUB_WIDTH-5;
                } else {
                    startX = (100 - SUB_WIDTH) / 2;
                }
            }

            if (LocalVideoRender != null) {
                LocalVideoRender.x = 0;
                LocalVideoRender.y = 0;
                LocalVideoRender.w = 100;
                LocalVideoRender.h = 100;
                LocalVideoRender.mLayout.setPosition(0, 0, 100, 100);
                LocalVideoRender.surfaceViewRenderer.requestLayout();
            }
            Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, VideoView> entry = iter.next();
                VideoView render = entry.getValue();

                if (orientation == LinearLayout.HORIZONTAL) {
                    if (direction == Gravity.CENTER) {
                        render.x = startX + (render.index - 1) * SUB_WIDTH;
                    } else if (direction == Gravity.LEFT) {
                        render.x = startX + (render.index - 1) * SUB_WIDTH;
                    } else if (direction == Gravity.RIGHT) {
                        render.x = startX - (render.index - 1) * SUB_WIDTH;
                    } else {
                        render.x = startX + (render.index - 1) * SUB_WIDTH;
                    }
                    render.y = startY;
                } else {
                    render.x=startX;
                    render.y = startY - (render.index - 1) * SUB_HEIGHT;
                }
                render.w = SUB_WIDTH;
                render.h = SUB_HEIGHT;
                render.mLayout.setPosition(render.x, render.y, render.w, render.h);
                render.surfaceViewRenderer.requestLayout();
            }
        }
    }

    /**
     * 适合横屏
     * 平均大小模式示例
     * 1个全屏 2个上下或左右个1  3个品字形状  4个田字形状 5个上2下3  6个上3下3
     */
    public void updateVideoViewSameSize() {
        int HEIGHT, WIDTH;
        //平均大小模式
        int size = mRemoteRenderList.size();
        if (size == 0) {
            LocalVideoRender.mLayout.setPosition(0, 0, 100, 100);
            LocalVideoRender.surfaceViewRenderer.requestLayout();
        } else if (size == 1) {
            if (!is169) {
                HEIGHT = (int) (((mScreenWidth / 2f) / 1.33333f) / (mScreenHeight / 100));
                WIDTH = (int) ((mScreenWidth / 2f) / (mScreenWidth / 100));
            } else {
                HEIGHT = (int) (((mScreenWidth / 2f) / 1.77777f) / (mScreenHeight / 100));
                WIDTH = (int) ((mScreenWidth / 2f) / (mScreenWidth / 100));
            }
            int Y = (100 - HEIGHT) / 2;
            Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, VideoView> entry = iter.next();
                VideoView render = entry.getValue();
                LocalVideoRender.mLayout.setPosition(0, Y, WIDTH, HEIGHT);
                LocalVideoRender.surfaceViewRenderer.requestLayout();
                if (render.index == 1) {
                    render.mLayout.setPosition(WIDTH, Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                }
            }
        } else if (size == 2) {
            if (!is169) {
                WIDTH = (int) (((mScreenHeight / 2f) * 1.33333f) / (mScreenWidth / 100));
                HEIGHT = (int) ((mScreenHeight / 2f) / (mScreenHeight / 100));
            } else {
                WIDTH = (int) (((mScreenHeight / 2f) * 1.77777f) / (mScreenWidth / 100));
                HEIGHT = (int) ((mScreenHeight / 2f) / (mScreenHeight / 100));
            }
            int X = 0;
            int Y = 0;
//            int WIDTH = 100 / 2;
//            int HEIGHT = 50;

            Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, VideoView> entry = iter.next();

                VideoView render = entry.getValue();
                LocalVideoRender.mLayout.setPosition((100 - WIDTH) / 2, Y, WIDTH, HEIGHT);
                LocalVideoRender.surfaceViewRenderer.requestLayout();
                if (render.index == 1) {
                    render.mLayout.setPosition((100 - 2 * WIDTH) / 2, Y + HEIGHT, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else if (render.index == 2) {
                    render.mLayout.setPosition((100 - 2 * WIDTH) / 2 + WIDTH, Y + HEIGHT, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                }
            }
        } else if (size == 3) {
            if (!is169) {
                WIDTH = (int) (((mScreenHeight / 2f) * 1.33333f) / (mScreenWidth / 100));
                HEIGHT = (int) ((mScreenHeight / 2f) / (mScreenHeight / 100));
            } else {
                WIDTH = (int) (((mScreenHeight / 2f) * 1.77777f) / (mScreenWidth / 100));
                HEIGHT = (int) ((mScreenHeight / 2f) / (mScreenHeight / 100));
            }
            int X = 0;
            int Y = 0;
//            int WIDTH = 50;
//            int HEIGHT = 50;
            Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, VideoView> entry = iter.next();
                VideoView render = entry.getValue();
                LocalVideoRender.mLayout.setPosition((100 - WIDTH * 2) / 2, Y, WIDTH, HEIGHT);
                LocalVideoRender.surfaceViewRenderer.requestLayout();
                if (render.index == 1) {
                    render.mLayout.setPosition((100 - 2 * WIDTH) / 2 + WIDTH, Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else if (render.index == 2) {
                    render.mLayout.setPosition((100 - 2 * WIDTH) / 2, Y + HEIGHT, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else if (render.index == 3) {
                    render.mLayout.setPosition((100 - 2 * WIDTH) / 2 + WIDTH, Y + HEIGHT, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                }
            }
        } else if (size == 4) {
            if (!is169) {
                WIDTH = (int) (((mScreenHeight / 2f) * 1.33333f) / (mScreenWidth / 100));
                HEIGHT = (int) ((mScreenHeight / 2f) / (mScreenHeight / 100));
            } else {
                HEIGHT = (int) (((mScreenWidth / 3f) / 1.77777f) / (mScreenHeight / 100));
                WIDTH = (int) ((mScreenWidth / 3f) / (mScreenWidth / 100));
            }
            int X = (100 - WIDTH * 3) / 2;
            int Y = (100-HEIGHT*2)/2;
            Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, VideoView> entry = iter.next();
                VideoView render = entry.getValue();
                LocalVideoRender.mLayout.setPosition((100 - WIDTH * 2) / 2, Y, WIDTH, HEIGHT);
                LocalVideoRender.surfaceViewRenderer.requestLayout();
                if (render.index == 1) {
                    render.mLayout.setPosition((100 - WIDTH * 2) / 2 + WIDTH, Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else {
                    if (render.index % 3 == 0) {
                        render.mLayout.setPosition(X, Y + HEIGHT, WIDTH, HEIGHT);
                        render.surfaceViewRenderer.requestLayout();
                    } else {
                        render.mLayout.setPosition(X + (render.index % 3 * WIDTH), Y + HEIGHT, WIDTH, HEIGHT);
                        render.surfaceViewRenderer.requestLayout();
                    }

                }

            }
        } else {
            if (!is169) {
                WIDTH = (int) (((mScreenHeight / 2f) * 1.33333f) / (mScreenWidth / 100));
                HEIGHT = (int) ((mScreenHeight / 2f) / (mScreenHeight / 100));
            } else {
                HEIGHT = (int) (((mScreenWidth / 3f) / 1.77777f) / (mScreenHeight / 100));
                WIDTH = (int) ((mScreenWidth / 3f) / (mScreenWidth / 100));
            }
            int X = (100 - WIDTH * 3) / 2;
            int Y = (100-HEIGHT*2)/2;
//            int WIDTH = 100 / 3;
//            int HEIGHT = 30;
            Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, VideoView> entry = iter.next();
                VideoView render = entry.getValue();
                LocalVideoRender.mLayout.setPosition(X, Y, WIDTH, HEIGHT);
                LocalVideoRender.surfaceViewRenderer.requestLayout();
                if (render.index == 1) {
                    render.mLayout.setPosition(X + WIDTH, Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else if (render.index == 2) {
                    render.mLayout.setPosition(X + (WIDTH * 2), Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else if (render.index == 3) {
                    render.mLayout.setPosition(X, HEIGHT+Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else if (render.index == 4) {
                    render.mLayout.setPosition(X + WIDTH, HEIGHT+Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                } else if (render.index == 5) {
                    render.mLayout.setPosition(X + (WIDTH * 2), HEIGHT+Y, WIDTH, HEIGHT);
                    render.surfaceViewRenderer.requestLayout();
                }
            }
        }
        }



    private void SwitchViewToFullscreen(VideoView view1, VideoView fullscrnView) {
        if (view1==null||fullscrnView==null){
            return;
        }
        int index, x, y, w, h;

        index = view1.index;
        x = view1.x;
        y = view1.y;
        w = view1.w;
        h = view1.h;

        view1.index = fullscrnView.index;
        view1.x = fullscrnView.x;
        view1.y = fullscrnView.y;
        view1.w = fullscrnView.w;
        view1.h = fullscrnView.h;

        fullscrnView.index = index;
        fullscrnView.x = x;
        fullscrnView.y = y;
        fullscrnView.w = w;
        fullscrnView.h = h;

        fullscrnView.mLayout.setPosition(fullscrnView.x, fullscrnView.y, fullscrnView.w, fullscrnView.h);
        view1.mLayout.setPosition(view1.x, view1.y, view1.w, view1.h);

        updateVideoLayout(view1, fullscrnView);
    }
    /**
     * 视频切换后更新视频的布局
     *
     * @param view1
     * @param view2
     */
    private void updateVideoLayout(VideoView view1, VideoView view2) {
        if (view1.isFullScreen()) {
            view1.surfaceViewRenderer.setZOrderMediaOverlay(false);
            view2.surfaceViewRenderer.setZOrderMediaOverlay(true);
            view1.mLayout.requestLayout();
            view2.mLayout.requestLayout();
            rlVideoGroup.removeView(view1.mLayout);
            rlVideoGroup.removeView(view2.mLayout);
            rlVideoGroup.addView(view1.mLayout, -1);
            rlVideoGroup.addView(view2.mLayout, 0);
        } else if (view2.isFullScreen()) {
            view1.surfaceViewRenderer.setZOrderMediaOverlay(true);
            view2.surfaceViewRenderer.setZOrderMediaOverlay(false);
            view2.mLayout.requestLayout();
            view1.mLayout.requestLayout();
            rlVideoGroup.removeView(view1.mLayout);
            rlVideoGroup.removeView(view2.mLayout);
            rlVideoGroup.addView(view1.mLayout, 0);
            rlVideoGroup.addView(view2.mLayout, -1);
        } else {
            view1.mLayout.requestLayout();
            view2.mLayout.requestLayout();
            rlVideoGroup.removeView(view1.mLayout);
            rlVideoGroup.removeView(view2.mLayout);
            rlVideoGroup.addView(view1.mLayout, 0);
            rlVideoGroup.addView(view2.mLayout, 0);
        }
    }

    /**
     * 获取全屏的界面
     *
     * @return
     */
    private VideoView GetFullScreen() {
        if (LocalVideoRender.isFullScreen()) {
            return LocalVideoRender;
        }
        Iterator<Map.Entry<String, VideoView>> iter = mRemoteRenderList.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, VideoView> entry = iter.next();
            String peerId = entry.getKey();
            VideoView render = entry.getValue();
            if (render.isFullScreen())
                return render;
        }
        return null;
    }
}


================================================
FILE: app/src/main/java/org/ar/widgets/AppBaseDialogFragment.java
================================================
package org.ar.widgets;

import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by KathLine on 2016/12/30.
 */

public abstract class AppBaseDialogFragment extends DialogFragment {
    private View view;

    public AppBaseDialogFragment() {
        // Required empty public constructor
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);//必须放在setContextView之前调用, 去掉Dialog中的蓝线
//        view = LayoutInflater.from(getActivity()).inflate(getContentViewID(), container, false);
        view = inflater.inflate(getContentViewID(), container);
        setLayout();
        initData(view);
        return view;
    }

    protected void setLayout() {
    }

    @LayoutRes
    protected abstract int getContentViewID();

    protected abstract void initData(View view);
}


================================================
FILE: app/src/main/java/org/ar/widgets/BaseDialog.java
================================================
package org.ar.widgets;

import android.app.Dialog;
import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

/**
 * Created by KathLine on 2016/11/8.
 */

public abstract class BaseDialog extends Dialog {

    public BaseDialog(Context context) {
        super(context);
    }

    protected abstract void onTouchOutside();

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        /* 触摸外部弹窗 */
        if (isOutOfBounds(getContext(), event)) {
            onTouchOutside();
        }
        return super.onTouchEvent(event);
    }

    /**
     * 判断当前用户触摸是否超出了Dialog的显示区域
     *
     * @param context
     * @param event
     * @return
     */
    private boolean isOutOfBounds(Context context, MotionEvent event) {
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
        final View decorView = getWindow().getDecorView();
        return (x < -slop) || (y < -slop) || (x > (decorView.getWidth() + slop))
                || (y > (decorView.getHeight() + slop));
    }
}


================================================
FILE: app/src/main/java/org/ar/widgets/CustomDialog.java
================================================
package org.ar.widgets;

import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;

import org.ar.rtmpc.R;


/**
 * Created by KathLine on 2016/8/2.
 */
public class CustomDialog extends BaseDialog {

    protected Builder builder;
    protected int layoutId;
    protected int gravity;
    protected int animId;
    protected boolean backgroundDrawableable;
    protected float dimAmount;
    protected boolean cancelable;
    protected boolean existDialogLined;
    public boolean isFullScreen;
    protected int width;
    protected int height;

    protected CustomDialog(Context context, Builder builder) {
        super(context);
        this.builder = builder;
        layoutId = builder.layoutId;
        gravity = builder.gravity;
        animId = builder.animId;
        backgroundDrawableable = builder.backgroundDrawableable;
        dimAmount = builder.dimAmount;
        cancelable = builder.cancelable;
        existDialogLined = builder.existDialogLined;
        isFullScreen = builder.isFullScreen;
        width = builder.width;
        height = builder.height;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (existDialogLined) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
        }
        setContentView(layoutId);
        Window window = getWindow();
        window.setGravity(gravity);
        window.setWindowAnimations(animId);
        window.getDecorView().setPadding(0, 0, 0, 0);
        WindowManager.LayoutParams lp = window.getAttributes();
        if (width != 0 && height != 0) {
            lp.width = width;
            lp.height = height;
        }
        if (isFullScreen) {
            window.setFlags(
                    WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置全屏,即没有系统状态栏
        }
        if (backgroundDrawableable) {
            window.setBackgroundDrawable(new ColorDrawable(0));
        }
        if (dimAmount < 0f || dimAmount > 1f) {
            throw new RuntimeException("透明度必须在0~1之间");
        }else {
            lp.dimAmount = dimAmount;
        }
        window.setAttributes(lp);
        setCancelable(cancelable);
        if (cancelable) {
            setCanceledOnTouchOutside(true);
        }
    }

    @Override
    protected void onTouchOutside() {
        if (onTouchOutsideListener != null){
            onTouchOutsideListener.touchOutSide();
        }
    }

    public interface onTouchOutsideListener{
        void touchOutSide();
    }

    public onTouchOutsideListener onTouchOutsideListener;

    public void setOnTouchOutsideListener(onTouchOutsideListener listener){
        onTouchOutsideListener = listener;
    }

    public Builder getBuilder() {
        return builder;
    }

    public CustomDialog show(Builder.onInitListener listener) {
        this.show();
        if (listener != null) {
            listener.init(this);
        }
        return this;
    }

    public static class Builder {
        public Context context;
        public int layoutId;
        public int gravity;
        public int animId;
        public boolean backgroundDrawableable;
        public float dimAmount;
        public boolean cancelable;
        public boolean existDialogLined;
        public boolean isFullScreen;
        public int width;
        public int height;

        public Builder(Context context) {
            this.context = context;
            layoutId = R.layout.dialog_base;
            gravity = Gravity.CENTER;
            animId = R.style.default_dialog_style;
            backgroundDrawableable = false;
            dimAmount = 0.5f;
            cancelable = true;
            existDialogLined = true;
            width = 0;
            height = 0;
        }

        public Builder setContentView(@LayoutRes int layoutId) {
            this.layoutId = layoutId;
            return this;
        }

        /**
         * 必须使用Gravity的静态常量,默认在中间弹出
         *
         * @param gravity 详见{@link Gravity}
         * @return
         * @see Gravity
         */
        public Builder setGravity(int gravity) {
            this.gravity = gravity;
            return this;
        }

        /**
         * 设置Dialog弹出和Dialog退出的动画
         *
         * @param animId
         * @return
         */
        public Builder setAnimId(int animId) {
            this.animId = animId;
            return this;
        }

        /**
         * Creates a new set of layout parameters with the specified width
         * and height.
         *
         * @param width  the width, either set WindowManager.LayoutParams.WRAP_CONTENT or
         *               WindowManager.LayoutParams.FILL_PARENT (replaced by WindowManager.LayoutParams.MATCH_PARENT in
         *               API Level 8), or a fixed size in pixels
         * @param height the height, either set WindowManager.LayoutParams.WRAP_CONTENT or
         *               WindowManager.LayoutParams.FILL_PARENT (replaced by WindowManager.LayoutParams.MATCH_PARENT in
         *               API Level 8), or a fixed size in pixels
         * @return
         */
        public Builder setLayoutParams(int width, int height) {
            this.width = width;
            this.height = height;
            return this;
        }

        /**
         * 是否给Dialog的背景设置透明,默认false
         *
         * @param backgroundDrawableable
         * @return
         */
        public Builder setBackgroundDrawable(boolean backgroundDrawableable) {
            this.backgroundDrawableable = backgroundDrawableable;
            return this;
        }

        /**
         * 设置Dialog之外的背景透明度,0~1之间,默认值 0.5f,半透明
         *
         * @param dimAmount
         * @return
         */
        public Builder setDimAmount(float dimAmount) {
            this.dimAmount = dimAmount;
            return this;
        }

        /**
         * 设置Dialog是否可以关闭在Dialog之外的区域,默认true
         *
         * @param cancelable
         * @return
         */
        public Builder setCancelable(boolean cancelable) {
            this.cancelable = cancelable;
            return this;
        }

        /**
         * 如果存在Holo主题下Dialog有蓝色线(含有标题栏)可以尝试调用该方法,默认不存在
         *
         * @param existDialogLined
         * @return
         */
        public Builder setExistDialogLined(boolean existDialogLined) {
            this.existDialogLined = existDialogLined;
            return this;
        }

        /**
         * 是否设置全屏模式,指的是去除系统状态栏,默认不去除
         *
         * @param isFullScreen
         * @return
         */
        public Builder setFullScreen(boolean isFullScreen) {
            this.isFullScreen = isFullScreen;
            return this;
        }

        public interface onInitListener {
            /**
             * 绑定控件
             *
             * @param customDialog
             */
            void init(CustomDialog customDialog);
        }

        public CustomDialog build() {
            return new CustomDialog(context, this);
        }

        /**
         * 如果对话框仅仅起提示作用,可以传入null
         *
         * @param listener
         * @return
         */
        public CustomDialog show(onInitListener listener) {
            CustomDialog dialog = build();
            dialog.show();
            if (listener != null) {
                listener.init(dialog);
            }
            return dialog;
        }
    }
}


================================================
FILE: app/src/main/java/org/ar/widgets/KeyboardDialogFragment.java
================================================
package org.ar.widgets;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.graphics.drawable.ColorDrawable;
import android.support.v4.app.DialogFragment;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import org.ar.rtmpc.R;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by KathLine on 2016/12/30.
 */

public class KeyboardDialogFragment extends AppBaseDialogFragment {

    TextView close;
    EditText editSendMessage;
    Button btnSend;
    private static InputMethodManager imm;
    public KeyboardDialogFragment() {
        // Required empty public constructor
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }




    public interface EdittextListener {
        void setTextStr(String text);

        void dismiss(DialogFragment dialogFragment);
    }

    private EdittextListener edittextListener;

    public void setEdittextListener(EdittextListener listener) {
        edittextListener = listener;
    }

    @Override
    protected void setLayout() {
        Window window = getDialog().getWindow();
        window.getDecorView().setPadding(0, 0, 0, 0);
        window.setBackgroundDrawable(new ColorDrawable(0));//背景透明
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
        lp.height =ViewGroup.LayoutParams.MATCH_PARENT;
        lp.dimAmount = 0;
        window.setAttributes(lp);
    }

    @Override
    protected int getContentViewID() {
        return R.layout.dialogfragment_keyboard;
    }

    @Override
    protected void initData(View view) {
        close=view.findViewById(R.id.close);
        close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (edittextListener != null) {
                    hideKeyboard();
                   dismiss();
                }
            }
        });
        editSendMessage=view.findViewById(R.id.edit_send_message);
        btnSend=view.findViewById(R.id.btn_send);

        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String text = editSendMessage.getText().toString();
                if (!TextUtils.isEmpty(text)) {
                    if (edittextListener != null) {
                        edittextListener.setTextStr(text);
                        editSendMessage.setText("");
                        hideKeyboard();
                        dismiss();
                    }
                }
            }
        });
        Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                               public void run() {
                                  showKeyboard(editSendMessage.getContext(), editSendMessage);
                               }
                           },
                    150);

    }


    private void hideKeyboard() {
        try {
            InputMethodManager imm = (InputMethodManager) editSendMessage.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            if (imm!=null&&getDialog()!=null) {
                imm.hideSoftInputFromWindow(getDialog().getCurrentFocus().getWindowToken(),
                        InputMethodManager.HIDE_NOT_ALWAYS);
            }
        }catch (Exception e){
        }

    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if (edittextListener != null) {
Download .txt
gitextract_zej5ynzh/

├── .gitignore
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── org/
│       │           └── ar/
│       │               └── rtmpc/
│       │                   └── ApplicationTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── org/
│       │   │       └── ar/
│       │   │           ├── ARApplication.java
│       │   │           ├── BaseActivity.java
│       │   │           ├── DeveloperInfo.java
│       │   │           ├── SplashActivity.java
│       │   │           ├── adapter/
│       │   │           │   ├── AudioLineAdapter.java
│       │   │           │   ├── LiveLineAdapter.java
│       │   │           │   ├── LiveListAdapter.java
│       │   │           │   ├── LiveMessageAdapter.java
│       │   │           │   └── LogAdapter.java
│       │   │           ├── guest/
│       │   │           │   ├── AudioGuestActivity.java
│       │   │           │   ├── GuestActivity.java
│       │   │           │   └── LiveListActivity.java
│       │   │           ├── hoster/
│       │   │           │   ├── AudioHosterActivity.java
│       │   │           │   ├── HosterActivity.java
│       │   │           │   └── LineFragment.java
│       │   │           ├── model/
│       │   │           │   ├── LineBean.java
│       │   │           │   ├── LiveBean.java
│       │   │           │   └── MessageBean.java
│       │   │           ├── utils/
│       │   │           │   ├── ARUtils.java
│       │   │           │   ├── DisplayUtils.java
│       │   │           │   ├── MD5.java
│       │   │           │   ├── NameUtils.java
│       │   │           │   ├── PermissionsCheckUtil.java
│       │   │           │   ├── ScreenUtils.java
│       │   │           │   └── ToastUtil.java
│       │   │           └── widgets/
│       │   │               ├── ARVideoView.java
│       │   │               ├── AppBaseDialogFragment.java
│       │   │               ├── BaseDialog.java
│       │   │               ├── CustomDialog.java
│       │   │               └── KeyboardDialogFragment.java
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── push_bottom_in.xml
│       │       │   └── push_bottom_out.xml
│       │       ├── color/
│       │       │   └── select_text_host_input.xml
│       │       ├── drawable/
│       │       │   ├── bg_host_head.xml
│       │       │   ├── bg_list_item.xml
│       │       │   ├── bg_white.xml
│       │       │   ├── default_input_bg.xml
│       │       │   ├── line_anim.xml
│       │       │   ├── list_item_bg.xml
│       │       │   ├── selector_apply.xml
│       │       │   ├── shape_creat_btn_bg.xml
│       │       │   ├── shape_edittext_bg.xml
│       │       │   ├── shape_home_green_btn.xml
│       │       │   ├── shape_meet_id.xml
│       │       │   ├── shape_message.xml
│       │       │   ├── shape_popuwindow.xml
│       │       │   ├── shape_room_apply_audio_line.xml
│       │       │   ├── shape_room_apply_line.xml
│       │       │   ├── shape_room_hang_up_line.xml
│       │       │   ├── shape_room_member.xml
│       │       │   ├── shape_room_message.xml
│       │       │   └── shape_room_name.xml
│       │       ├── drawable-xxhdpi/
│       │       │   ├── selector_video_manager.xml
│       │       │   ├── shape_back_btn.xml
│       │       │   ├── shape_index_button.xml
│       │       │   └── shape_index_solid_button.xml
│       │       ├── layout/
│       │       │   ├── activity_audio_guest.xml
│       │       │   ├── activity_audio_hoster.xml
│       │       │   ├── activity_guest.xml
│       │       │   ├── activity_hoster.xml
│       │       │   ├── activity_live_list.xml
│       │       │   ├── dialog_base.xml
│       │       │   ├── dialogfragment_keyboard.xml
│       │       │   ├── empty_act_data.xml
│       │       │   ├── empty_no_line_data.xml
│       │       │   ├── fragment_line.xml
│       │       │   ├── item_audio_line.xml
│       │       │   ├── item_line.xml
│       │       │   ├── item_line_list.xml
│       │       │   ├── item_live.xml
│       │       │   ├── item_live_chat.xml
│       │       │   ├── item_member.xml
│       │       │   ├── item_more_futures.xml
│       │       │   └── layout_arvideo.xml
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── ids.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── values-w820dp/
│       │           └── dimens.xml
│       └── test/
│           └── java/
│               └── org/
│                   └── ar/
│                       └── rtmpc/
│                           └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Download .txt
SYMBOL INDEX (346 symbols across 32 files)

FILE: app/src/androidTest/java/org/ar/rtmpc/ApplicationTest.java
  class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
    method ApplicationTest (line 10) | public ApplicationTest() {

FILE: app/src/main/java/org/ar/ARApplication.java
  class ARApplication (line 14) | public class ARApplication extends Application {
    method onCreate (line 20) | @Override
    method App (line 34) | public  static Application App(){
    method getNickName (line 38) | public static String getNickName(){

FILE: app/src/main/java/org/ar/BaseActivity.java
  class BaseActivity (line 14) | public abstract class BaseActivity extends AppCompatActivity {
    method onSaveInstanceState (line 17) | @Override
    method onCreate (line 22) | @Override
    method ProgressDialog (line 30) | private void ProgressDialog(Context ctx) {
    method showProgressDialog (line 37) | public void showProgressDialog() {
    method hiddenProgressDialog (line 45) | public void hiddenProgressDialog() {
    method onDestroy (line 51) | @Override
    method setContentView (line 59) | @Override
    method startAnimActivity (line 65) | public void startAnimActivity(Class<?> cls) {
    method finishAnimActivity (line 69) | public void finishAnimActivity() {
    method startAnimActivity (line 73) | public void startAnimActivity(Class<?> cls, Bundle bundle) {
    method getLayoutId (line 79) | public abstract int getLayoutId();
    method initView (line 81) | public abstract void initView(Bundle savedInstanceState);

FILE: app/src/main/java/org/ar/DeveloperInfo.java
  class DeveloperInfo (line 5) | public class DeveloperInfo {

FILE: app/src/main/java/org/ar/SplashActivity.java
  class SplashActivity (line 9) | public class SplashActivity extends Activity {
    method onCreate (line 11) | @Override

FILE: app/src/main/java/org/ar/adapter/AudioLineAdapter.java
  class AudioLineAdapter (line 16) | public class AudioLineAdapter extends BaseQuickAdapter<LineBean,BaseView...
    method AudioLineAdapter (line 18) | public AudioLineAdapter(boolean isHost) {
    method convert (line 23) | @Override

FILE: app/src/main/java/org/ar/adapter/LiveLineAdapter.java
  class LiveLineAdapter (line 15) | public class LiveLineAdapter extends BaseQuickAdapter<LineBean,BaseViewH...
    method LiveLineAdapter (line 16) | public LiveLineAdapter() {
    method convert (line 20) | @Override

FILE: app/src/main/java/org/ar/adapter/LiveListAdapter.java
  class LiveListAdapter (line 17) | public class LiveListAdapter extends BaseQuickAdapter<LiveBean,BaseViewH...
    method LiveListAdapter (line 19) | public LiveListAdapter() {
    method convert (line 23) | @Override

FILE: app/src/main/java/org/ar/adapter/LiveMessageAdapter.java
  class LiveMessageAdapter (line 14) | public class LiveMessageAdapter extends BaseQuickAdapter<MessageBean, Ba...
    method LiveMessageAdapter (line 15) | public LiveMessageAdapter() {
    method convert (line 19) | @Override

FILE: app/src/main/java/org/ar/adapter/LogAdapter.java
  class LogAdapter (line 12) | public class LogAdapter extends BaseQuickAdapter<String,BaseViewHolder> {
    method LogAdapter (line 13) | public LogAdapter() {
    method convert (line 17) | @Override

FILE: app/src/main/java/org/ar/guest/AudioGuestActivity.java
  class AudioGuestActivity (line 45) | public class AudioGuestActivity extends BaseActivity implements BaseQuic...
    method onKeyDown (line 69) | @Override
    method onDestroy (line 80) | @Override
    method getLayoutId (line 98) | @Override
    method initView (line 103) | @Override
    method getUserData (line 152) | public String getUserData() {
    method onAudioManagerChangedState (line 166) | private void onAudioManagerChangedState() {
    method ShowExitDialog (line 173) | private void ShowExitDialog() {
    method addChatMessageList (line 206) | private void addChatMessageList(MessageBean chatMessageBean) {
    method printLog (line 221) | public void printLog(String log){
    method onRtmpPlayerOk (line 234) | @Override
    method onRtmpPlayerStart (line 250) | @Override
    method onRtmpPlayerStatus (line 265) | @Override
    method onRtmpPlayerLoading (line 282) | @Override
    method onRtmpPlayerClosed (line 296) | @Override
    method onRTCJoinLineResult (line 311) | @Override
    method onRTCApplyLineResult (line 339) | @Override
    method onRTCHangupLine (line 365) | @Override
    method onRTCOpenRemoteVideoRender (line 383) | @Override
    method onRTCCloseRemoteVideoRender (line 388) | @Override
    method onRTCOpenRemoteAudioLine (line 393) | @Override
    method onRTCCloseRemoteAudioLine (line 414) | @Override
    method onRTCLocalAudioActive (line 433) | @Override
    method onRTCHosterAudioActive (line 443) | @Override
    method onRTCRemoteAudioActive (line 454) | @Override
    method onRTCRemoteAVStatus (line 475) | @Override
    method onRTCLineLeave (line 489) | @Override
    method onRTCUserMessage (line 513) | @Override
    method onRTCMemberNotify (line 528) | @Override
    method onClick (line 542) | public void onClick(View view) {
    method showChatLayout (line 585) | private void showChatLayout() {
    method onItemChildClick (line 602) | @Override

FILE: app/src/main/java/org/ar/guest/GuestActivity.java
  class GuestActivity (line 46) | public class GuestActivity extends BaseActivity {
    method onKeyDown (line 66) | @Override
    method onDestroy (line 77) | @Override
    method getLayoutId (line 96) | @Override
    method onCreate (line 101) | @Override
    method initView (line 108) | @Override
    method getUserData (line 167) | public String getUserData() {
    method onAudioManagerChangedState (line 180) | private void onAudioManagerChangedState() {
    method ShowExitDialog (line 187) | private void ShowExitDialog() {
    method addChatMessageList (line 219) | private void addChatMessageList(MessageBean chatMessageBean) {
    method printLog (line 235) | public void printLog(String log){
    method onRtmpPlayerOk (line 248) | @Override
    method onRtmpPlayerStart (line 264) | @Override
    method onRtmpPlayerStatus (line 279) | @Override
    method onRtmpPlayerLoading (line 297) | @Override
    method onRtmpPlayerClosed (line 311) | @Override
    method onRTCJoinLineResult (line 326) | @Override
    method onRTCApplyLineResult (line 349) | @Override
    method onRTCHangupLine (line 379) | @Override
    method onRTCOpenRemoteVideoRender (line 398) | @Override
    method onRTCCloseRemoteVideoRender (line 410) | @Override
    method onRTCOpenRemoteAudioLine (line 424) | @Override
    method onRTCCloseRemoteAudioLine (line 429) | @Override
    method onRTCLocalAudioActive (line 434) | @Override
    method onRTCHosterAudioActive (line 444) | @Override
    method onRTCRemoteAudioActive (line 455) | @Override
    method onRTCRemoteAVStatus (line 465) | @Override
    method onRTCLineLeave (line 479) | @Override
    method onRTCUserMessage (line 518) | @Override
    method onRTCMemberNotify (line 533) | @Override
    method onClick (line 550) | public void onClick(View view) {
    method showChatLayout (line 593) | private void showChatLayout() {

FILE: app/src/main/java/org/ar/guest/LiveListActivity.java
  class LiveListActivity (line 43) | public class LiveListActivity extends BaseActivity implements SwipeRefre...
    method getLayoutId (line 52) | @Override
    method initView (line 57) | @Override
    method onResume (line 78) | @Override
    method getEmptyView (line 84) | public View getEmptyView(){
    method onRefresh (line 95) | @Override
    method onItemClick (line 101) | @Override
    method getLiveList (line 114) | private void getLiveList() {
    method onClick (line 164) | @Override
    method onKeyDown (line 192) | @Override

FILE: app/src/main/java/org/ar/hoster/AudioHosterActivity.java
  class AudioHosterActivity (line 49) | public class AudioHosterActivity extends BaseActivity implements BaseQui...
    method onResume (line 70) | @Override
    method onPause (line 75) | @Override
    method onKeyDown (line 80) | @Override
    method onDestroy (line 88) | @Override
    method getLayoutId (line 106) | @Override
    method initView (line 111) | @Override
    method getLiveInfo (line 156) | public String getLiveInfo(String pullUrl, String hlsUrl) {
    method getUserData (line 173) | public String getUserData() {
    method onAudioManagerChangedState (line 187) | private void onAudioManagerChangedState() {
    method addChatMessageList (line 200) | private void addChatMessageList(MessageBean chatMessageBean) {
    method showChatLayout (line 216) | private void showChatLayout() {
    method ShowExitDialog (line 233) | private void ShowExitDialog() {
    method printLog (line 256) | public void printLog(String log){
    method onRtmpStreamOk (line 268) | @Override
    method onRtmpStreamReconnecting (line 285) | @Override
    method onRtmpStreamStatus (line 301) | @Override
    method onRtmpStreamFailed (line 319) | @Override
    method onRtmpStreamClosed (line 335) | @Override
    method onRTCCreateLineResult (line 355) | @Override
    method onRTCApplyToLine (line 382) | @Override
    method onRTCCancelLine (line 407) | @Override
    method onRTCOpenRemoteVideoRender (line 433) | @Override
    method onRTCCloseRemoteVideoRender (line 438) | @Override
    method onRTCOpenRemoteAudioLine (line 443) | @Override
    method onRTCCloseRemoteAudioLine (line 460) | @Override
    method onRTCLocalAudioActive (line 480) | @Override
    method onRTCRemoteAudioActive (line 491) | @Override
    method onRTCRemoteAVStatus (line 513) | @Override
    method onRTCLineClosed (line 532) | @Override
    method onRTCUserMessage (line 550) | @Override
    method onRTCMemberNotify (line 565) | @Override
    method onClick (line 579) | public void onClick(View view) {
    method initLineFragment (line 610) | private void initLineFragment() {
    method SetLineListener (line 637) | public void SetLineListener(HosterActivity.LineListener mLineListener) {
    method onItemChildClick (line 642) | @Override

FILE: app/src/main/java/org/ar/hoster/HosterActivity.java
  class HosterActivity (line 52) | public class HosterActivity extends BaseActivity {
    method onKeyDown (line 74) | @Override
    method onDestroy (line 82) | @Override
    method getLayoutId (line 99) | @Override
    method initView (line 104) | @Override
    method getLiveInfo (line 188) | public String getLiveInfo(String pullUrl,String hlsUrl) {
    method getUserData (line 205) | public String getUserData() {
    method onAudioManagerChangedState (line 219) | private void onAudioManagerChangedState() {
    method onCloseVideoRender (line 231) | @Override
    method addChatMessageList (line 243) | private void addChatMessageList(MessageBean chatMessageBean) {
    method showChatLayout (line 260) | private void showChatLayout() {
    method ShowExitDialog (line 276) | private void ShowExitDialog() {
    method printLog (line 304) | public void printLog(String log){
    method onRtmpStreamOk (line 315) | @Override
    method onRtmpStreamReconnecting (line 332) | @Override
    method onRtmpStreamStatus (line 350) | @Override
    method onRtmpStreamFailed (line 367) | @Override
    method onRtmpStreamClosed (line 383) | @Override
    method onRTCCreateLineResult (line 400) | @Override
    method onRTCApplyToLine (line 425) | @Override
    method onRTCCancelLine (line 452) | @Override
    method onRTCOpenRemoteVideoRender (line 478) | @Override
    method onRTCCloseRemoteVideoRender (line 492) | @Override
    method onRTCOpenRemoteAudioLine (line 507) | @Override
    method onRTCCloseRemoteAudioLine (line 512) | @Override
    method onRTCLocalAudioActive (line 521) | @Override
    method onRTCRemoteAudioActive (line 532) | @Override
    method onRTCRemoteAVStatus (line 542) | @Override
    method onRTCLineClosed (line 557) | @Override
    method onRTCUserMessage (line 588) | @Override
    method onRTCMemberNotify (line 603) | @Override
    method onClick (line 618) | public void onClick(View view) {
    method initLineFragment (line 656) | private void initLineFragment() {
    type LineListener (line 685) | public interface LineListener {
      method AddAudioGuest (line 686) | void AddAudioGuest(LineBean lineBean, ARRtmpcHosterKit hosterKit);
      method AddGuest (line 688) | void AddGuest(LineBean lineBean, ARRtmpcHosterKit hosterKit);
      method RemoveGuest (line 690) | void RemoveGuest(String peerid);
    method SetLineListener (line 693) | public void SetLineListener(LineListener mLineListener) {
    method closeLineDialog (line 697) | public void closeLineDialog() {

FILE: app/src/main/java/org/ar/hoster/LineFragment.java
  class LineFragment (line 24) | public class LineFragment extends Fragment implements HosterActivity.Lin...
    method onCreateView (line 34) | @Nullable
    method AddAudioGuest (line 62) | @Override
    method AddGuest (line 69) | @Override
    method RemoveGuest (line 76) | @Override
    method onItemChildClick (line 90) | @Override
    method getmAadapter (line 127) | public LiveLineAdapter getmAadapter() {

FILE: app/src/main/java/org/ar/model/LineBean.java
  class LineBean (line 7) | public class LineBean {
    method LineBean (line 13) | public LineBean(String peerId, String name,boolean isSelf) {
    method isStartAnim (line 19) | public boolean isStartAnim() {
    method setStartAnim (line 23) | public void setStartAnim(boolean startAnim) {
    method isSelf (line 27) | public boolean isSelf() {
    method setSelf (line 31) | public void setSelf(boolean self) {

FILE: app/src/main/java/org/ar/model/LiveBean.java
  class LiveBean (line 9) | public class LiveBean implements Serializable{
    method getmRtmpPullUrl (line 22) | public String getmRtmpPullUrl() {
    method setmRtmpPullUrl (line 26) | public void setmRtmpPullUrl(String mRtmpPullUrl) {
    method getmHlsUrl (line 30) | public String getmHlsUrl() {
    method setmHlsUrl (line 34) | public void setmHlsUrl(String mHlsUrl) {
    method getmPushUrl (line 38) | public String getmPushUrl() {
    method setmPushUrl (line 42) | public void setmPushUrl(String mPushUrl) {
    method getmLiveTopic (line 46) | public String getmLiveTopic() {
    method setmLiveTopic (line 50) | public void setmLiveTopic(String mLiveTopic) {
    method getmAnyrtcId (line 54) | public String getmAnyrtcId() {
    method setmAnyrtcId (line 58) | public void setmAnyrtcId(String mAnyrtcId) {
    method getIsAudioLive (line 62) | public int getIsAudioLive() {
    method setIsAudioLive (line 66) | public void setIsAudioLive(int isAudioLive) {
    method getIsLiveLandscape (line 70) | public int getIsLiveLandscape() {
    method setIsLiveLandscape (line 74) | public void setIsLiveLandscape(int isLiveLandscape) {
    method getLiveMode (line 78) | public int getLiveMode() {
    method setLiveMode (line 82) | public void setLiveMode(int liveMode) {
    method getmHostName (line 86) | public String getmHostName() {
    method setmHostName (line 90) | public void setmHostName(String mHostName) {
    method getmMemberNum (line 94) | public String getmMemberNum() {
    method setmMemberNum (line 98) | public void setmMemberNum(String mMemberNum) {

FILE: app/src/main/java/org/ar/model/MessageBean.java
  class MessageBean (line 7) | public class MessageBean {
    method MessageBean (line 15) | public MessageBean(int type, String name, String content) {

FILE: app/src/main/java/org/ar/utils/ARUtils.java
  type ARUtils (line 10) | public enum ARUtils {
    method ARUtils (line 37) | ARUtils(int value) {
    method getValue (line 41) | public int getValue() {
    method getErrString (line 50) | public static String getErrString(int value) {

FILE: app/src/main/java/org/ar/utils/DisplayUtils.java
  class DisplayUtils (line 7) | public class DisplayUtils {
    method px2dp (line 11) | public static int px2dp(Context context, float pxValue) {
    method dp2px (line 19) | public static int dp2px(Context context, float dpValue) {
    method px2sp (line 27) | public static int px2sp(Context context, float pxValue) {
    method sp2px (line 35) | public static int sp2px(Context context, float spValue) {
    method getScreenWidthPixels (line 43) | public static int getScreenWidthPixels(Activity context) {
    method getScreenHeightPixels (line 52) | public static int getScreenHeightPixels(Activity context) {

FILE: app/src/main/java/org/ar/utils/MD5.java
  class MD5 (line 9) | public class MD5 {
    method getMD5 (line 11) | public static String getMD5(String password ) {

FILE: app/src/main/java/org/ar/utils/NameUtils.java
  class NameUtils (line 8) | public class NameUtils {
    method getNickName (line 26) | public static String getNickName() {

FILE: app/src/main/java/org/ar/utils/PermissionsCheckUtil.java
  class PermissionsCheckUtil (line 11) | public class PermissionsCheckUtil {
    method showMissingPermissionDialog (line 21) | public static void showMissingPermissionDialog(final Activity activity...
    method startAppSettings (line 56) | public static void startAppSettings(Activity activity) {

FILE: app/src/main/java/org/ar/utils/ScreenUtils.java
  class ScreenUtils (line 18) | public class ScreenUtils {
    method ScreenUtils (line 19) | private ScreenUtils() {
    method dip2Dimension (line 31) | public static float dip2Dimension(float dip, Context context) {
    method dpToP (line 36) | public static int dpToP(Resources paramResources, int paramInt) {
    method toDimension (line 47) | public static float toDimension(float dip, Context context, int comple...
    method getScreenWidth (line 58) | public static int getScreenWidth(Context context) {
    method getScreenHeight (line 72) | public static int getScreenHeight(Context context) {
    method isPad (line 85) | public static boolean isPad(Context context) {
    method getStatusHeight (line 110) | public static int getStatusHeight(Context context) {
    method snapShotWithStatusBar (line 130) | public static Bitmap snapShotWithStatusBar(Activity activity) {
    method snapShotWithoutStatusBar (line 150) | public static Bitmap snapShotWithoutStatusBar(Activity activity) {
    method getHeightInPx (line 168) | public static final int getHeightInPx(Context context) {
    method getWidthInPx (line 173) | public static final int getWidthInPx(Context context) {
    method getHeightInDp (line 178) | public static final int getHeightInDp(Context context) {
    method getWidthInDp (line 184) | public static final int getWidthInDp(Context context) {
    method dip2px (line 190) | public static int dip2px(Context context, float dpValue) {
    method px2dip (line 195) | public static int px2dip(Context context, float pxValue) {
    method px2sp (line 200) | public static int px2sp(Context context, float pxValue) {
    method sp2px (line 205) | public static int sp2px(Context context, float spValue) {

FILE: app/src/main/java/org/ar/utils/ToastUtil.java
  class ToastUtil (line 14) | public class ToastUtil {
    method show (line 18) | public static void show(int resId) {
    method show (line 22) | public static void show(int resId, int duration) {
    method show (line 26) | public static void show(CharSequence text) {
    method show (line 30) | public static void show(CharSequence text, int duration) {
    method show (line 42) | public static void show(int resId, Object... args) {
    method show (line 47) | public static void show(String format, Object... args) {
    method show (line 51) | public static void show(int resId, int duration, Object... args) {
    method show (line 56) | public static void show(String format, int duration, Object... args) {
    method cancelToast (line 60) | public void cancelToast() {

FILE: app/src/main/java/org/ar/widgets/ARVideoView.java
  class ARVideoView (line 35) | public class ARVideoView implements View.OnTouchListener{
    type VideoLayoutOnclickEvent (line 63) | public interface VideoLayoutOnclickEvent {
      method onCloseVideoRender (line 64) | void onCloseVideoRender(View view, String strPeerId);
    method setVideoLayoutOnclickEvent (line 68) | public void setVideoLayoutOnclickEvent(VideoLayoutOnclickEvent videoLa...
    method ARVideoView (line 72) | public ARVideoView(RelativeLayout rlVideoGroup, EglBase eglBase, Conte...
    method setVideoSwitchEnable (line 84) | public void setVideoSwitchEnable(boolean enable) {
    method onTouch (line 90) | @Override
    class VideoView (line 134) | protected static class VideoView {
      method VideoView (line 147) | public VideoView(String videoId, Context ctx, EglBase eglBase, int i...
      method isFullScreen (line 171) | public Boolean isFullScreen() {
      method Hited (line 182) | public Boolean Hited(int px, int py) {
      method close (line 195) | public void close() {
    method setVideoViewLayout (line 212) | public void setVideoViewLayout(boolean is169, int direction, int orien...
    method changeSizeWhenRotate (line 226) | public void changeSizeWhenRotate(boolean isFirst) {
    method getVideoRenderSize (line 258) | public int getVideoRenderSize() {
    method openLocalVideoRender (line 272) | public VideoRenderer openLocalVideoRender() {
    method removeLocalVideoRender (line 311) | public void removeLocalVideoRender() {
    method openRemoteVideoRender (line 332) | public VideoRenderer openRemoteVideoRender(final String videoId) {
    method removeRemoteRender (line 386) | public void removeRemoteRender(String videoId) {
    method sortVideoRenderIndex (line 401) | public void sortVideoRenderIndex() {
    method updateVideoView1Big (line 416) | private void updateVideoView1Big() {
    method updateVideoViewSameSize (line 493) | public void updateVideoViewSameSize() {
    method SwitchViewToFullscreen (line 648) | private void SwitchViewToFullscreen(VideoView view1, VideoView fullscr...
    method updateVideoLayout (line 683) | private void updateVideoLayout(VideoView view1, VideoView view2) {
    method GetFullScreen (line 717) | private VideoView GetFullScreen() {

FILE: app/src/main/java/org/ar/widgets/AppBaseDialogFragment.java
  class AppBaseDialogFragment (line 15) | public abstract class AppBaseDialogFragment extends DialogFragment {
    method AppBaseDialogFragment (line 18) | public AppBaseDialogFragment() {
    method onCreateView (line 22) | @Nullable
    method setLayout (line 33) | protected void setLayout() {
    method getContentViewID (line 36) | @LayoutRes
    method initData (line 39) | protected abstract void initData(View view);

FILE: app/src/main/java/org/ar/widgets/BaseDialog.java
  class BaseDialog (line 13) | public abstract class BaseDialog extends Dialog {
    method BaseDialog (line 15) | public BaseDialog(Context context) {
    method onTouchOutside (line 19) | protected abstract void onTouchOutside();
    method onTouchEvent (line 21) | @Override
    method isOutOfBounds (line 37) | private boolean isOutOfBounds(Context context, MotionEvent event) {

FILE: app/src/main/java/org/ar/widgets/CustomDialog.java
  class CustomDialog (line 17) | public class CustomDialog extends BaseDialog {
    method CustomDialog (line 31) | protected CustomDialog(Context context, Builder builder) {
    method onCreate (line 46) | @Override
    method onTouchOutside (line 82) | @Override
    type onTouchOutsideListener (line 89) | public interface onTouchOutsideListener{
      method touchOutSide (line 90) | void touchOutSide();
    method setOnTouchOutsideListener (line 95) | public void setOnTouchOutsideListener(onTouchOutsideListener listener){
    method getBuilder (line 99) | public Builder getBuilder() {
    method show (line 103) | public CustomDialog show(Builder.onInitListener listener) {
    class Builder (line 111) | public static class Builder {
      method Builder (line 124) | public Builder(Context context) {
      method setContentView (line 137) | public Builder setContentView(@LayoutRes int layoutId) {
      method setGravity (line 149) | public Builder setGravity(int gravity) {
      method setAnimId (line 160) | public Builder setAnimId(int animId) {
      method setLayoutParams (line 177) | public Builder setLayoutParams(int width, int height) {
      method setBackgroundDrawable (line 189) | public Builder setBackgroundDrawable(boolean backgroundDrawableable) {
      method setDimAmount (line 200) | public Builder setDimAmount(float dimAmount) {
      method setCancelable (line 211) | public Builder setCancelable(boolean cancelable) {
      method setExistDialogLined (line 222) | public Builder setExistDialogLined(boolean existDialogLined) {
      method setFullScreen (line 233) | public Builder setFullScreen(boolean isFullScreen) {
      type onInitListener (line 238) | public interface onInitListener {
        method init (line 244) | void init(CustomDialog customDialog);
      method build (line 247) | public CustomDialog build() {
      method show (line 257) | public CustomDialog show(onInitListener listener) {

FILE: app/src/main/java/org/ar/widgets/KeyboardDialogFragment.java
  class KeyboardDialogFragment (line 28) | public class KeyboardDialogFragment extends AppBaseDialogFragment {
    method KeyboardDialogFragment (line 34) | public KeyboardDialogFragment() {
    method onConfigurationChanged (line 39) | @Override
    type EdittextListener (line 47) | public interface EdittextListener {
      method setTextStr (line 48) | void setTextStr(String text);
      method dismiss (line 50) | void dismiss(DialogFragment dialogFragment);
    method setEdittextListener (line 55) | public void setEdittextListener(EdittextListener listener) {
    method setLayout (line 59) | @Override
    method getContentViewID (line 71) | @Override
    method initData (line 76) | @Override
    method hideKeyboard (line 116) | private void hideKeyboard() {
    method onDismiss (line 128) | @Override
    method hideKeyboard (line 136) | public  void hideKeyboard(Context context, View view) {
    method hideKeyboard (line 150) | public  void hideKeyboard(Activity activity) {
    method showKeyboard (line 163) | public  void showKeyboard(Context context, View view) {

FILE: app/src/test/java/org/ar/rtmpc/ExampleUnitTest.java
  class ExampleUnitTest (line 10) | public class ExampleUnitTest {
    method addition_isCorrect (line 11) | @Test
Condensed preview — 100 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (305K chars).
[
  {
    "path": ".gitignore",
    "chars": 647,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n#\n\n*.iml.gradle/\nlocal."
  },
  {
    "path": "README.md",
    "chars": 2335,
    "preview": "# 重要提醒\nanyRTC 对该版本已经不再维护。[前往新版本](https://github.com/anyRTC/ArAndroidSDK).\n\n**新版本功能如下:**\n- 频道管理\n- 音频管理\n- 视频管理\n- 音频文件播放及混音"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 1228,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n    buildToolsVersion '27.0.3'\n    defaultCo"
  },
  {
    "path": "app/gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Fri Mar 15 15:28:49 CST 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "app/gradlew",
    "chars": 5296,
    "preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up"
  },
  {
    "path": "app/gradlew.bat",
    "chars": 2176,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 3537,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
  },
  {
    "path": "app/src/androidTest/java/org/ar/rtmpc/ApplicationTest.java",
    "chars": 343,
    "preview": "package org.ar.rtmpc;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 2555,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "app/src/main/java/org/ar/ARApplication.java",
    "chars": 1112,
    "preview": "package org.ar;\n\nimport android.app.Application;\n\nimport com.yanzhenjie.nohttp.InitializationConfig;\nimport com.yanzhenj"
  },
  {
    "path": "app/src/main/java/org/ar/BaseActivity.java",
    "chars": 2116,
    "preview": "package org.ar;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimpor"
  },
  {
    "path": "app/src/main/java/org/ar/DeveloperInfo.java",
    "chars": 239,
    "preview": "package org.ar;\n\n\n\npublic class DeveloperInfo {\n\n\n\n\n    public final static String APPID = \"\";\n\n    public final static "
  },
  {
    "path": "app/src/main/java/org/ar/SplashActivity.java",
    "chars": 396,
    "preview": "package org.ar;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport org.ar.gu"
  },
  {
    "path": "app/src/main/java/org/ar/adapter/AudioLineAdapter.java",
    "chars": 1032,
    "preview": "package org.ar.adapter;\n\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.chad.library.adapter.base"
  },
  {
    "path": "app/src/main/java/org/ar/adapter/LiveLineAdapter.java",
    "chars": 713,
    "preview": "package org.ar.adapter;\n\nimport android.widget.TextView;\n\nimport com.chad.library.adapter.base.BaseQuickAdapter;\nimport "
  },
  {
    "path": "app/src/main/java/org/ar/adapter/LiveListAdapter.java",
    "chars": 1359,
    "preview": "package org.ar.adapter;\n\nimport android.graphics.drawable.Drawable;\nimport android.widget.TextView;\n\nimport com.chad.lib"
  },
  {
    "path": "app/src/main/java/org/ar/adapter/LiveMessageAdapter.java",
    "chars": 719,
    "preview": "package org.ar.adapter;\n\nimport android.graphics.Color;\n\nimport com.chad.library.adapter.base.BaseQuickAdapter;\nimport c"
  },
  {
    "path": "app/src/main/java/org/ar/adapter/LogAdapter.java",
    "chars": 664,
    "preview": "package org.ar.adapter;\n\nimport android.graphics.Color;\nimport android.widget.TextView;\n\nimport com.chad.library.adapter"
  },
  {
    "path": "app/src/main/java/org/ar/guest/AudioGuestActivity.java",
    "chars": 22628,
    "preview": "package org.ar.guest;\n\nimport android.content.DialogInterface;\nimport android.graphics.drawable.AnimationDrawable;\nimpor"
  },
  {
    "path": "app/src/main/java/org/ar/guest/GuestActivity.java",
    "chars": 21641,
    "preview": "package org.ar.guest;\n\nimport android.annotation.SuppressLint;\nimport android.content.DialogInterface;\nimport android.me"
  },
  {
    "path": "app/src/main/java/org/ar/guest/LiveListActivity.java",
    "chars": 7982,
    "preview": "package org.ar.guest;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.widget.SwipeRe"
  },
  {
    "path": "app/src/main/java/org/ar/hoster/AudioHosterActivity.java",
    "chars": 22544,
    "preview": "package org.ar.hoster;\n\nimport android.content.DialogInterface;\nimport android.media.AudioManager;\nimport android.os.Bun"
  },
  {
    "path": "app/src/main/java/org/ar/hoster/HosterActivity.java",
    "chars": 24051,
    "preview": "package org.ar.hoster;\n\nimport android.content.DialogInterface;\nimport android.media.AudioManager;\nimport android.os.Bun"
  },
  {
    "path": "app/src/main/java/org/ar/hoster/LineFragment.java",
    "chars": 4437,
    "preview": "package org.ar.hoster;\n\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4."
  },
  {
    "path": "app/src/main/java/org/ar/model/LineBean.java",
    "chars": 653,
    "preview": "package org.ar.model;\n\n/**\n * Created by liuxiaozhong on 2017/9/24.\n */\n\npublic class LineBean {\n    public String peerI"
  },
  {
    "path": "app/src/main/java/org/ar/model/LiveBean.java",
    "chars": 2083,
    "preview": "package org.ar.model;\n\nimport java.io.Serializable;\n\n/**\n * Created by liuxiaozhong on 2017-09-22.\n */\n\npublic class Liv"
  },
  {
    "path": "app/src/main/java/org/ar/model/MessageBean.java",
    "chars": 438,
    "preview": "package org.ar.model;\n\n/**\n * Created by liuxiaozhong on 2017-09-22.\n */\n\npublic class MessageBean {\n    public final st"
  },
  {
    "path": "app/src/main/java/org/ar/utils/ARUtils.java",
    "chars": 2822,
    "preview": "package org.ar.utils;\n\nimport org.ar.ARApplication;\nimport org.ar.rtmpc.R;\n\n/**\n * Created by Skyline on 2016/11/1.\n */\n"
  },
  {
    "path": "app/src/main/java/org/ar/utils/DisplayUtils.java",
    "chars": 1456,
    "preview": "package org.ar.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.util.DisplayMetrics;\n"
  },
  {
    "path": "app/src/main/java/org/ar/utils/MD5.java",
    "chars": 1041,
    "preview": "package org.ar.utils;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * Create"
  },
  {
    "path": "app/src/main/java/org/ar/utils/NameUtils.java",
    "chars": 2373,
    "preview": "package org.ar.utils;\n\nimport java.util.Random;\n\n/**\n * Created by Skyline on 2016/8/8.\n */\npublic class NameUtils {\n   "
  },
  {
    "path": "app/src/main/java/org/ar/utils/PermissionsCheckUtil.java",
    "chars": 2024,
    "preview": "package org.ar.utils;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.DialogInterfa"
  },
  {
    "path": "app/src/main/java/org/ar/utils/ScreenUtils.java",
    "chars": 6457,
    "preview": "package org.ar.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.res.Resources"
  },
  {
    "path": "app/src/main/java/org/ar/utils/ToastUtil.java",
    "chars": 1808,
    "preview": "package org.ar.utils;\n\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.Gravity;\nimpo"
  },
  {
    "path": "app/src/main/java/org/ar/widgets/ARVideoView.java",
    "chars": 29014,
    "preview": "package org.ar.widgets;\n\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.graphi"
  },
  {
    "path": "app/src/main/java/org/ar/widgets/AppBaseDialogFragment.java",
    "chars": 1138,
    "preview": "package org.ar.widgets;\n\nimport android.os.Bundle;\nimport android.support.annotation.LayoutRes;\nimport android.support.a"
  },
  {
    "path": "app/src/main/java/org/ar/widgets/BaseDialog.java",
    "chars": 1183,
    "preview": "package org.ar.widgets;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.view.MotionEvent;\nimp"
  },
  {
    "path": "app/src/main/java/org/ar/widgets/CustomDialog.java",
    "chars": 7617,
    "preview": "package org.ar.widgets;\n\nimport android.content.Context;\nimport android.graphics.drawable.ColorDrawable;\nimport android."
  },
  {
    "path": "app/src/main/java/org/ar/widgets/KeyboardDialogFragment.java",
    "chars": 5202,
    "preview": "package org.ar.widgets;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.DialogInter"
  },
  {
    "path": "app/src/main/res/anim/push_bottom_in.xml",
    "chars": 334,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <translate\n "
  },
  {
    "path": "app/src/main/res/anim/push_bottom_out.xml",
    "chars": 333,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <translate\n "
  },
  {
    "path": "app/src/main/res/color/select_text_host_input.xml",
    "chars": 261,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "app/src/main/res/drawable/bg_host_head.xml",
    "chars": 422,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/bg_list_item.xml",
    "chars": 374,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "app/src/main/res/drawable/bg_white.xml",
    "chars": 553,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <ite"
  },
  {
    "path": "app/src/main/res/drawable/default_input_bg.xml",
    "chars": 925,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "app/src/main/res/drawable/line_anim.xml",
    "chars": 539,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animation-list xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/drawable/list_item_bg.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "app/src/main/res/drawable/selector_apply.xml",
    "chars": 303,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "app/src/main/res/drawable/shape_creat_btn_bg.xml",
    "chars": 233,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/shape_edittext_bg.xml",
    "chars": 225,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/shape_home_green_btn.xml",
    "chars": 204,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid and"
  },
  {
    "path": "app/src/main/res/drawable/shape_meet_id.xml",
    "chars": 231,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\""
  },
  {
    "path": "app/src/main/res/drawable/shape_message.xml",
    "chars": 287,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\""
  },
  {
    "path": "app/src/main/res/drawable/shape_popuwindow.xml",
    "chars": 244,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/shape_room_apply_audio_line.xml",
    "chars": 209,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <solid"
  },
  {
    "path": "app/src/main/res/drawable/shape_room_apply_line.xml",
    "chars": 207,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <solid"
  },
  {
    "path": "app/src/main/res/drawable/shape_room_hang_up_line.xml",
    "chars": 207,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <solid"
  },
  {
    "path": "app/src/main/res/drawable/shape_room_member.xml",
    "chars": 223,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <solid"
  },
  {
    "path": "app/src/main/res/drawable/shape_room_message.xml",
    "chars": 222,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <solid"
  },
  {
    "path": "app/src/main/res/drawable/shape_room_name.xml",
    "chars": 223,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <solid"
  },
  {
    "path": "app/src/main/res/drawable-xxhdpi/selector_video_manager.xml",
    "chars": 278,
    "preview": "<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_selected=\"false\" android:d"
  },
  {
    "path": "app/src/main/res/drawable-xxhdpi/shape_back_btn.xml",
    "chars": 251,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable-xxhdpi/shape_index_button.xml",
    "chars": 877,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  Copyright (C) 2015. Keegan小钢(http://keeganlee.me)\n\n  Licensed under the Apa"
  },
  {
    "path": "app/src/main/res/drawable-xxhdpi/shape_index_solid_button.xml",
    "chars": 875,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  Copyright (C) 2015. Keegan小钢(http://keeganlee.me)\n\n  Licensed under the Apa"
  },
  {
    "path": "app/src/main/res/layout/activity_audio_guest.xml",
    "chars": 9357,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns"
  },
  {
    "path": "app/src/main/res/layout/activity_audio_hoster.xml",
    "chars": 8442,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/activity_guest.xml",
    "chars": 7944,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xm"
  },
  {
    "path": "app/src/main/res/layout/activity_hoster.xml",
    "chars": 7565,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xm"
  },
  {
    "path": "app/src/main/res/layout/activity_live_list.xml",
    "chars": 3611,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/dialog_base.xml",
    "chars": 1292,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/dialogfragment_keyboard.xml",
    "chars": 1990,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/empty_act_data.xml",
    "chars": 961,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/layout/empty_no_line_data.xml",
    "chars": 601,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/layout/fragment_line.xml",
    "chars": 1203,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/item_audio_line.xml",
    "chars": 1279,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/item_line.xml",
    "chars": 1467,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/layout/item_line_list.xml",
    "chars": 487,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/item_live.xml",
    "chars": 2064,
    "preview": "<android.support.v7.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://sch"
  },
  {
    "path": "app/src/main/res/layout/item_live_chat.xml",
    "chars": 782,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/layout/item_member.xml",
    "chars": 713,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/layout/item_more_futures.xml",
    "chars": 455,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     and"
  },
  {
    "path": "app/src/main/res/layout/layout_arvideo.xml",
    "chars": 1377,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "chars": 563,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- 圆形头像 -->\n    <declare-styleable name=\"CustomRoundView\">\n    "
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "chars": 4621,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">@color/main_red</color>\n    <color nam"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "chars": 1882,
    "preview": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal"
  },
  {
    "path": "app/src/main/res/values/ids.xml",
    "chars": 102,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <item name=\"wave_view\" type=\"id\"/>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 3597,
    "preview": "<resources>\n    <string name=\"app_name\">AR直播连麦</string>\n    <string name=\"str_title\">AR Live Hybird</string>\n    <string"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 1574,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "chars": 358,
    "preview": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as s"
  },
  {
    "path": "app/src/test/java/org/ar/rtmpc/ExampleUnitTest.java",
    "chars": 305,
    "preview": "package org.ar.rtmpc;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * To work on unit tests, switch t"
  },
  {
    "path": "build.gradle",
    "chars": 526,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Wed Sep 13 13:52:57 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 887,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
  },
  {
    "path": "gradlew",
    "chars": 4971,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "settings.gradle",
    "chars": 15,
    "preview": "include ':app'\n"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the AnyRTC/RTMPCHybridEngine-Android GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 100 files (271.6 KB), approximately 68.2k tokens, and a symbol index with 346 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!