直播互动的功能,最终选择了腾讯云平台进行开发,LiveRoom组件里面包含了(直播,连麦,弹幕,私信等)功能,我们需要的是推流,拉流都交个腾讯云来处理,腾讯云这方面功能也是比较齐全的了(粗略大概2分钟可看完本文,能像我写如此详细的全网暂时木有可以说,如果你是第一次接触直播可谓福音不敢说,无需自己后台一小时让你拥有直播app不在话下!文末有巨型福利相送及手写FFmpeg推流拉流教程源码+高清视频)。
而且腾讯云直播也是按照流量收费的,没有其他任何费用,所以如果要使用腾讯云直播+IM聊天(基本免费按日活收费)功能的,最好还是全部选用腾讯一家即可。
网上相关的文章很少,而且大厂的文档虽然高级但看起来集成过程还是有点慢的,
我这篇文章主要是手把手详细介绍Android 快速集成腾讯移动直播,无需后台任何配合我们前端直接调试成功!看完本文大概十分钟,半天搞定整个直播互动连麦。集成路上大概可以帮助大家节省一天时间,希望可以帮助到各位.

下载SDK
1.功能不同多种版本可以选择,一般来说,选择全功能专业版就好了.
官网集成到AS步骤:https://cloud.tencent.com/document/product/454/7877
个人用你 qq号登录后即可下载,
另外开通直播云服务:https://cloud.tencent.com/document/product/267/13551
以及IM云通信功能:https://console.cloud.tencent.com/avc 创建应用,点击购买开通一元基础版即可满足调试。


下载SDK后首先,运行Demo源码,跑通源码直接看到效果是最好的。建议先在demo源码上改动来实现调试成功

运行Domo项目后你可以试试可以在线看到同样使用本SDK demo 的用户在上面调试,你只需要把项目里的sdkAppId 和直播云appId 替换到你自己的项目,就可以替换成你再腾讯云开通的直播服务和使用你刚刚创建的项目的Im聊天连麦功能了。但是这里面还是有一些步骤的,不是简单的替换就可以的。

首先我建议你用debug的方式,在点击美女直播,到点击直播列表,到进入直播聊天室,以及新建直播间,这一部分多打一些断点,你就大概知道带直播连麦的直播聊天功能大致流程是:登录聊天室–获取推流地址–直播。 这里的登录是必须的步骤,直播和云通信是互通的,你可以用这一行代码来检测是否登录云通信成功:String loginUser = TIMManager.getInstance().getLoginUser();有返回值说明已经IMSDk初始化登录成功了。

如果你仔细想先用demo测试下 推流 拉流是否成功,那么可以先配置好播放域名,然后利用demo里的 首页—调试工具—RTMP推流,将你的在腾讯云直播生成推流地址出复制–粘贴到输入框–点击底部开始按钮–查看是否推流成功–log,然后电脑下载VLC播放器,打开—网络流播放—将的在腾讯云直播生成播放地址粘贴—播放,即可测试是否推流,拉流成功。具体见下面步骤:

播放域名设置:https://console.cloud.tencent.com/live/domainmanage

如下图,一定是绿色标记显示了,才说明你的域名设置成功并cname成功了,否则是不会播放成功的,这里要是你自己的备案的域名,如果你没有可以阿里云购买,然后申请备案,可能需要你购买一个云服务器才会送备案号,有了域名后解析是需要注意,如果你的是域名比如是abc.cn 阿里云的解析设置里 记录类型请填@,记录值亲填腾讯后台记录值那里给你自动生成的那一串全部。如果你的是www.abc.cn 那么记录类型填www 否则是不会成功的哦。配置后可以ping下是能看到腾讯的服务器地址就算配置ok了。但是一定时要下图中的绿色标记显示了才算完全正常哦!


推流,拉流地址生成:https://console.cloud.tencent.com/live/livecodemanage
推流域名可以先不设置自己的,默认已经给你生成了。至此你如果你不需要互动连麦的功能,只需要用腾讯的点播播放器就可以直接播放你生成的播放观看实时直播了。

后台对接腾讯云
我们推流,拉流都是交给腾讯云处理的,
LiveRoom 为什么需要 login?

LiveRoom 单靠一个终端的组件无法独自运行,它依赖一个后台服务为其实现房间管理和状态协调,这个后台服务我们称之为房间服务(RoomService)。而要使用这个房间服务,LiveRoom 就需要先进行登录(login)。

login 有很多参数需要填写,我应当如何填写这些参数呢?

如下表格中列举了三种填写方案,每种方案都有其适用场景:方案一适合调试;方案二适合快速上线;方案三适合自行定制;
你可有看下图:
https://cloud.tencent.com/document/product/454/14606



login(serverDomain, sdkAppID, accType, userID, userSig),可以看到登录索要的参数,accountType 是云通信后台你创建项目IM 配置那里可以生成的,userId是你的真实项目你的用户userId用户唯一标识即可,只有userSig 是需要后台生成的,但是这个我们调试阶段可以在客户端生成方便是一样的,
你也可以直接复制下面的生成userSig ,

package com.tencent.liteav.demo.webrtc;import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.Charset;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.zip.Deflater;public class WebRTCSigApi {private int mSdkAppid = 0;private PrivateKey mPrivateKey = null;private PublicKey mPublicKey = null;/*** 设置sdkappid* @param sdkappid*/public void setSdkAppid(int sdkappid) {this.mSdkAppid = sdkappid;}/*** 设置私钥 如果要生成userSig和privateMapKey则需要私钥* @param privateKey 私钥文件内容*/public void setPrivateKey(String privateKey) {String privateKeyPEM = privateKey.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replace("\r\n", "");char[] chars = privateKeyPEM.toCharArray();byte[] encodedKey = Base64.decode(chars);//Base64.getDecoder().decode(privateKeyPEM.getBytes());try {PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);KeyFactory keyFactory = KeyFactory.getInstance("EC");this.mPrivateKey = keyFactory.generatePrivate(keySpec);} catch (Exception e) {e.printStackTrace();}}/*** 设置公钥 如果要验证userSig和privateMapKey则需要公钥* @param publicKey 公钥文件内容*/public void setPublicKey(String publicKey) {String publicKeyPEM = publicKey.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").replace("\n", "");byte[] encodedKey = Base64.decode(publicKeyPEM.toCharArray());//Base64.getDecoder().decode(publicKeyPEM.getBytes());try {X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);KeyFactory keyFactory = KeyFactory.getInstance("EC");this.mPublicKey = keyFactory.generatePublic(keySpec);} catch (Exception e) {e.printStackTrace();}}/*** ECDSA-SHA256签名* @param data 需要签名的数据* @return 签名*/public byte[] sign(byte[] data) {try {Signature signer = Signature.getInstance("SHA256withECDSA");signer.initSign(this.mPrivateKey);signer.update(data);return signer.sign();} catch (Exception e) {e.printStackTrace();}return null;}/*** 验证ECDSA-SHA256签名* @param data 需要验证的数据原文* @param sig 需要验证的签名* @return true:验证成功 false:验证失败*/public boolean verify(byte[] data, byte[] sig) {try {Signature signer = Signature.getInstance("SHA256withECDSA");signer.initVerify(this.mPublicKey);signer.update(data);return signer.verify(sig);} catch (Exception e) {e.printStackTrace();}return false;}/*** 用于url的base64encode* '+' => '*', '/' => '-', '=' => '_'* @param data 需要编码的数据* @return 编码后的base64数据*/private byte[] base64UrlEncode(byte[] data) {char[] encode1 = Base64.encode(data);byte[] encode =new String(encode1).getBytes();
//        byte[] encode = Base64.encode(data);//Base64.getEncoder().encode(data);for (int i = 0; i < encode.length; i++) {if (encode[i] == '+') {encode[i] = '*';} else if (encode[i] == '/') {encode[i] = '-';} else if (encode[i] == '=') {encode[i] = '_';}}return encode;}/*** 用于url的base64decode* '*' => '+', '-' => '/', '_' => '='* @param data 需要解码的数据* @return 解码后的数据*/private byte[] base64UrlDecode(byte[] data) {byte[] encode = Arrays.copyOf(data, data.length);for (int i = 0; i < encode.length; i++) {if (encode[i] == '*') {encode[i] = '+';} else if (encode[i] == '-') {encode[i] = '/';} else if (encode[i] == '_') {encode[i] = '=';}}return encode;}/*** 生成userSig* @param userid 用户名* @param expire userSig有效期,出于安全考虑建议为300秒,您可以根据您的业务场景设置其他值。* @return 生成的userSig*/public String genUserSig(String userid, int expire) {String time = String.valueOf(System.currentTimeMillis()/1000);String serialString ="TLS.appid_at_3rd:" + 0 + "\n" +"TLS.account_type:" + 0 + "\n" +"TLS.identifier:" + userid + "\n" +"TLS.sdk_appid:" + this.mSdkAppid + "\n" +"TLS.time:" + time + "\n" +"TLS.expire_after:" + expire +"\n";byte[] signBytes = sign(serialString.getBytes(Charset.forName("UTF-8")));char[] encode = Base64.encode(signBytes);String sig = new String(encode);
//        String sig = Base64.encode(signBytes);//Base64.getEncoder().encodeToString(signBytes);String jsonString = "{"+ "\"TLS.account_type\":\"" + 0 +"\","+"\"TLS.identifier\":\"" + userid +"\","+"\"TLS.appid_at_3rd\":\"" + 0 +"\","+"\"TLS.sdk_appid\":\"" + this.mSdkAppid +"\","+"\"TLS.expire_after\":\"" + expire +"\","+"\"TLS.sig\":\"" + sig +"\","+"\"TLS.time\":\"" + time +"\","+"\"TLS.version\": \"201512300000\""+"}";//compressionDeflater compresser = new Deflater();compresser.setInput(jsonString.getBytes(Charset.forName("UTF-8")));compresser.finish();byte [] compressBytes = new byte [512];int compressBytesLength = compresser.deflate(compressBytes);compresser.end();String userSig = new String(base64UrlEncode(Arrays.copyOfRange(compressBytes, 0, compressBytesLength)));return userSig;}/*** 生成privateMapKey* @param userid 用户名* @param roomid 房间号* @param expire privateMapKey有效期,出于安全考虑建议为300秒,您可以根据您的业务场景设置其他值。* @return 生成的privateMapKey*/public String genPrivateMapKey(String userid, int roomid, int expire) {String time = String.valueOf(System.currentTimeMillis()/1000);//视频校验位需要用到的字段/*cVer    unsigned char/1 版本号,填0wAccountLen unsigned short /2   第三方自己的帐号长度buffAccount wAccountLen 第三方自己的帐号字符dwSdkAppid  unsigned int/4  sdkappiddwRoomId    unsigned int/4  群组号码dwExpTime   unsigned int/4  过期时间 (当前时间 + 有效期(单位:秒,建议300秒))dwPrivilegeMap  unsigned int/4  权限位dwAccountType   unsigned int/4  第三方帐号类型*/int accountLength = userid.length();int offset = 0;byte[] bytes = new byte[1+2+accountLength+4+4+4+4+4];//cVerbytes[offset++] = 0;//wAccountLenbytes[offset++] = (byte)((accountLength & 0xFF00) >> 8);bytes[offset++] = (byte)(accountLength & 0x00FF);//buffAccountfor (; offset < 3 + accountLength; ++offset) {bytes[offset] = (byte)userid.charAt(offset - 3);}//dwSdkAppidbytes[offset++] = (byte)((this.mSdkAppid & 0xFF000000) >> 24);bytes[offset++] = (byte)((this.mSdkAppid & 0x00FF0000) >> 16);bytes[offset++] = (byte)((this.mSdkAppid & 0x0000FF00) >> 8);bytes[offset++] = (byte)(this.mSdkAppid & 0x000000FF);//dwAuthIdlong nRoomId = Long.valueOf(roomid);bytes[offset++] = (byte)((nRoomId & 0xFF000000) >> 24);bytes[offset++] = (byte)((nRoomId & 0x00FF0000) >> 16);bytes[offset++] = (byte)((nRoomId & 0x0000FF00) >> 8);bytes[offset++] = (byte)(nRoomId & 0x000000FF);//dwExpTimelong expiredTime = Long.valueOf(time) + expire;bytes[offset++] = (byte)((expiredTime & 0xFF000000) >> 24);bytes[offset++] = (byte)((expiredTime & 0x00FF0000) >> 16);bytes[offset++] = (byte)((expiredTime & 0x0000FF00) >> 8);bytes[offset++] = (byte)(expiredTime & 0x000000FF);//dwPrivilegeMap     bytes[offset++] = (byte)((255 & 0xFF000000) >> 24);bytes[offset++] = (byte)((255 & 0x00FF0000) >> 16);bytes[offset++] = (byte)((255 & 0x0000FF00) >> 8);bytes[offset++] = (byte)(255 & 0x000000FF);//dwAccountTypebytes[offset++] = (byte)((0 & 0xFF000000) >> 24);bytes[offset++] = (byte)((0 & 0x00FF0000) >> 16);bytes[offset++] = (byte)((0 & 0x0000FF00) >> 8);bytes[offset++] = (byte)(0 & 0x000000FF);char[] encode = Base64.encode(bytes);String userbuf = new String(encode);
//        String userbuf = Base64.getEncoder().encodeToString(bytes);//Base64.getEncoder().encodeToString(bytes);String serialString ="TLS.appid_at_3rd:" + 0 + "\n" +"TLS.account_type:" + 0 + "\n" +"TLS.identifier:" + userid + "\n" +"TLS.sdk_appid:" + this.mSdkAppid + "\n" +"TLS.time:" + time + "\n" +"TLS.expire_after:" + expire +"\n" +"TLS.userbuf:" + userbuf + "\n";byte[] signBytes = sign(serialString.getBytes(Charset.forName("UTF-8")));char[] encodes = Base64.encode(signBytes);String sig = new String(encodes);
//        String sig = Base64.getEncoder().encodeToString(signBytes);//Base64.getEncoder().encodeToString(signBytes);String jsonString = "{"+"\"TLS.appid_at_3rd\":\"" + 0 +"\","+"\"TLS.account_type\":\"" + 0 +"\","+"\"TLS.identifier\":\"" + userid +"\","+"\"TLS.sdk_appid\":\"" + this.mSdkAppid +"\","+"\"TLS.expire_after\":\"" + expire +"\","+"\"TLS.sig\":\"" + sig +"\","+"\"TLS.time\":\"" + time +"\","+"\"TLS.userbuf\":\"" + userbuf +"\","+"\"TLS.version\": \"201512300000\""+"}";//compressionDeflater compresser = new Deflater();compresser.setInput(jsonString.getBytes(Charset.forName("UTF-8")));compresser.finish();byte [] compressBytes = new byte [512];int compressBytesLength = compresser.deflate(compressBytes);compresser.end();String privateMapKey = new String(base64UrlEncode(Arrays.copyOfRange(compressBytes, 0, compressBytesLength)));return privateMapKey;}/*  public static void main(String[] args) {int sdkappid = 140xxxxx;   //腾讯云云通信你创建的sdkappid int roomid = 1234;           //音视频房间号先随便填调试roomidString userid = "webrtc98";  //用户名userid 先随便填调试File privateKeyFile = new File("private_key");byte[] privateKey = new byte[(int)privateKeyFile.length()];File publicKeyFile = new File("public_key");byte[] publicKey = new byte[(int)publicKeyFile.length()];try {//读取私钥的内容//PS:不要把私钥文件暴露到外网直接下载了哦FileInputStream in1 = new FileInputStream(privateKeyFile);in1.read(privateKey);in1.close();//读取公钥的内容FileInputStream in2 = new FileInputStream(publicKeyFile);in2.read(publicKey);in2.close();} catch (Exception e ) {e.printStackTrace();}WebRTCSigApi api = new WebRTCSigApi();api.setSdkAppid(sdkappid);api.setPrivateKey(new String(privateKey));api.setPublicKey(new String(publicKey));//生成userSigString userSig = api.genUserSig(userid, 300);//生成privateMapKeyString privateMapKey = api.genPrivateMapKey(userid, roomid, 300);System.out.println("userSig:\n" + userSig);System.out.println("privateMapKey:\n" + privateMapKey);}*/}

base64类

/** Copyright (C) 2017 Baidu, Inc. All Rights Reserved.*/
package com.tencent.liteav.demo.webrtc;/*** Created by wangtianfei01 on 17/4/6.*/public class Base64 {private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();private static byte[] codes = new byte[256];public static char[] encode(byte[] data) {char[] out = new char[((data.length + 2) / 3) * 4];for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {boolean quad = false;boolean trip = false;int val = (0xFF & (int) data[i]);val <<= 8;if ((i + 1) < data.length) {val |= (0xFF & (int) data[i + 1]);trip = true;}val <<= 8;if ((i + 2) < data.length) {val |= (0xFF & (int) data[i + 2]);quad = true;}out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];val >>= 6;out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];val >>= 6;out[index + 1] = alphabet[val & 0x3F];val >>= 6;out[index + 0] = alphabet[val & 0x3F];}return out;}public static byte[] decode(char[] data) {int len = ((data.length + 3) / 4) * 3;if (data.length > 0 && data[data.length - 1] == '=') {--len;}if (data.length > 1 && data[data.length - 2] == '=') {--len;}byte[] out = new byte[len];int shift = 0;int accum = 0;int index = 0;for (int ix = 0; ix < data.length; ix++) {int value = codes[data[ix] & 0xFF];if (value >= 0) {accum <<= 6;shift += 6;accum |= value;if (shift >= 8) {shift -= 8;out[index++] = (byte) ((accum >> shift) & 0xff);}}}if (index != out.length) {throw new Error("miscalculated data length!");}return out;}static {for (int i = 0; i < 256; i++) {codes[i] = -1;}for (int i = 'A'; i <= 'Z'; i++) {codes[i] = (byte) (i - 'A');}for (int i = 'a'; i <= 'z'; i++) {codes[i] = (byte) (26 + i - 'a');}for (int i = '0'; i <= '9'; i++) {codes[i] = (byte) (52 + i - '0');}codes['+'] = 62;codes['/'] = 63;}
}

生成:

private void ininsig() {int sdkappid = 1400162038;   //腾讯云云通信sdkappid 1400162038int roomid = 1234;           //音视频房间号roomidString userid = "webrtc98777";  //用户名userid/*   File privateKeyFile = new File("private_key");byte[] privateKey = new byte[(int)privateKeyFile.length()];File publicKeyFile = new File("public_key");byte[] publicKey = new byte[(int)publicKeyFile.length()];try {//读取私钥的内容//PS:不要把私钥文件暴露到外网直接下载了哦FileInputStream in1 = new FileInputStream(privateKeyFile);in1.read(privateKey);in1.close();//读取公钥的内容FileInputStream in2 = new FileInputStream(publicKeyFile);in2.read(publicKey);in2.close();} catch (Exception e ) {e.printStackTrace();}*/WebRTCSigApi api = new WebRTCSigApi();api.setSdkAppid(sdkappid);
//        api.setPrivateKey(new String(privateKey));api.setPrivateKey("-----BEGIN PRIVATE KEY-----\r\n"+"你的IM创建项目设置里下载获取的私钥MBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg+eeR7R2n0cTcwmHj\r\n" + "你的IM创建项目设置里下载获取的私钥slopZXQycM/RznRQ/TjvaATNmbKcj\r\n" + "你的IM创建项目设置里下载获取的私钥mSNbq718jkTX\r\n"+"-----END PRIVATE KEY-----\r\n");
//        api.setPublicKey(new String(publicKey));//生成userSigString userSig = api.genUserSig(userid, 2000*50);SharedPreUtil.saveString(this,"userSig",userSig);System.out.println("privateMapKey:\n" + userSig);Toast.makeText(this, "sig:"+userSig, Toast.LENGTH_SHORT).show();}

建议你也可以自行阅读文档获取,因为这里面介绍了如何获取accountType 以及公钥私钥下载(后面用nodejs命令行注册腾讯云需要用到的,主要是在你下载的RoomTool 工具包里面的config.js文件修改):https://cloud.tencent.com/document/product/454/14548


点击 RoomTool.zip 下载腾讯云 RoomService 后台配置工具,这是一个基于 Node.js 的配置工具,需要您在使用前 安装 Node.js 。配置工具压缩包中包含的 pdf 和 PPT 有详细的配置说明,这里仅简要概括一下各个配置项的含义和作用。

修改config.js文件夹里面的请完全按照它的示例哦,不要以为那些提示是不用的了哈,如下图保留复制粘贴你的即可,

另外就是在生成userSig的时候,也是替换\t\r,文档里少了一个,坑死人了 会报一个错 ,注意哦。

config.js文件按照提示修改完毕后,按照nodejs环境后,注册腾讯云:打开命令行 cmd --,然后 运行:node setConfigInfo.js 1
根据提示运行后会显示请求成功的返回提示哦,如果你的私钥配置错误,会提示相应的错误,有时候提示不准确,还有就是你的播放域名要配置才可以哦。

到这里你如果还有什么问题你可以提交工单会有客服处理的或论坛搜索答案。

在调试的时候我们可以先写死:userId(注意如果用两个手机测试,这里需要改成不一样的否则IM或别踢出的报user not logged in),


直播SDK错误码对照表:https://cloud.tencent.com/document/product/454/8292
到这里就差不多了你可以用两个以上的手机(每个的userId都要唯一)同时在线调试直播并连麦了哈

Android集成腾讯直播(无需后台配合一小时让你拥有直播APP)相关推荐

  1. Android集成腾讯X5浏览器内核库

    Android集成腾讯X5浏览器内核库 一.相关配置 1. 相关地址 2.引入SDK 3. AndroidManifest配置 二.Application中初始化内核 三.代码实现 1. 自定义带Pr ...

  2. android腾讯互联demo,Android集成腾讯小直播Demo,multidex问题

    在集成腾讯官方的小直播源码中发现的问题 首先是android studio编译中中gradle不能下载gson等文件,需要用jcenter()把原来的maven注掉,或者在ProjectStructu ...

  3. android 集成腾讯定位,Android集成腾讯云通信IM

    本篇文章结构 一.集成流程. 二.集成中遇到的问题 集成过程 TIM图片20180425151417.png 很清楚,前几部没什么说的,去官网注册账号就好了,我们接下来看账号集成. 首先第一步是集成模 ...

  4. android 集成腾讯IMSDK4.2.9 TUIKIT即时通信之更改头像

    使用环境: 2018年集成的腾讯IM云通信,使用的是随心聊类似的集成方式. 2019年集成的时候,官方推荐TUIKIT依赖module github官方demo : https://github.co ...

  5. Android集成腾讯信鸽推送SDK

    推送是每个应用中常见的功能今天使用一下腾讯的信鸽推送听说信鸽推送保活率比较高~ 第一步先去官网注册账号https://xg.qq.com/推荐使用QQ直接登陆,进去之后点击"新建应用&quo ...

  6. android 集成腾讯地图定位

    本文只教学定位功能,需要搜索.2D或3D地图的可以到腾讯地图开发平台看api文档,链接:腾讯地图 一.到腾讯地图开发平下载定位sdk,快速入口:腾讯地图定位 二.在项目的AndroidManiFest ...

  7. 项目集成腾讯移动直播总结--后端

    最近项目新增直播带货需求,指定使用腾讯移动直播SDK,集成的过程也算是磕磕绊绊,因为以前自己没接触过,同事也没做过这一块,所以很多不清不楚的地方,而且是是多端集成,主播端在App直播,用户端是在小程序 ...

  8. Android基于腾讯云的小直播开发配置

    如何快速搭建小直播,请参考文档:https://cloud.tencent.com/document/product/454/7999 1. 小直播前后台结构图 腾讯云: 提供了云直播(LVB),点播 ...

  9. 安卓Android中腾讯音视频和直播 API的使用

    安卓Android中腾讯音视频和直播 API的使用 文章目录 安卓Android中腾讯音视频和直播 API的使用 前言:安卓Android中腾讯音视频和直播 API的使用,这里没有写UI,功能是放在一 ...

最新文章

  1. 苹果竟放出“流氓” APP
  2. Spring Hibernate Mybatis配置详解
  3. hdoj--2534--Score(gcd)
  4. linux 全新编译安装,全新linux中通过编译方式安装nginx
  5. ARIA and the value of challenge-led innovation
  6. Mac 安装rabbitmq
  7. qsort 三级排序
  8. HTTP和HTTPS回顾
  9. 计算机网络(六)——连接到Internet
  10. iText导出pdf,poi导出excel并下载到客户端
  11. Python内置函数(37)——sorted
  12. 机器学习算法总结之支持向量机(四)
  13. Git如何忽略已经上传的文件或文件夹?
  14. 对于Vue组件的初步认识(未整理)
  15. 清除eclipse当前登录的SVN账户
  16. 二、运行盛派的Demo(看下效果)
  17. C# 16进制转字符串,字符串转16进制
  18. GD32实战14__RTC
  19. W3school离线手册最新版下载
  20. gps84转换gcj02公式_WGS84-GCJ-02坐标转化

热门文章

  1. 在SwiftUI 2.0和Xcode 12中使用CoreData
  2. Jenkins-Multijob plugin多任务串并行
  3. DSP BootLoader 应用笔记(转珠海阿良的blog)
  4. 解决KeyError: ((1, 1, 3), ‘<i8‘) TypeError: Cannot handle this data type: (1, 1, 3), <i8
  5. Android 中屏幕进行横屏显示和竖屏显示的方法
  6. Ogre学习笔记(8):骨骼动画
  7. [附源码]计算机毕业设计Python-Steam游戏平台系统论文(程序+源码+LW文档)
  8. 阿里巴巴中国站获得1688商品类目 API
  9. Android调用照相机展示高清图片及展示图片时图片倾斜问题
  10. 西瓜书线性回归和最小二乘法公式推导