diff --git a/.gitignore b/.gitignore
index ced686fa..bc74c564 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,4 @@ _ReSharper*/
 /src/packages
 /packages
 /bin
+/src/.vs/Qiniu/v16/Server/sqlite3
diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json
new file mode 100644
index 00000000..6b611411
--- /dev/null
+++ b/.vs/VSWorkspaceState.json
@@ -0,0 +1,6 @@
+{
+  "ExpandedNodes": [
+    ""
+  ],
+  "PreviewInSolutionExplorer": false
+}
\ No newline at end of file
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
new file mode 100644
index 00000000..d93116eb
Binary files /dev/null and b/.vs/slnx.sqlite differ
diff --git a/src/Qiniu.sln b/src/Qiniu.sln
index 7db84cf9..1c4b5ee2 100644
--- a/src/Qiniu.sln
+++ b/src/Qiniu.sln
@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2002
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28803.156
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu", "Qiniu\Qiniu.csproj", "{2F5B0328-DE8B-4B53-A500-3077E340A51B}"
 EndProject
diff --git a/src/Qiniu/Pili/PiliManager.cs b/src/Qiniu/Pili/PiliManager.cs
new file mode 100644
index 00000000..9c6761f3
--- /dev/null
+++ b/src/Qiniu/Pili/PiliManager.cs
@@ -0,0 +1,79 @@
+using Qiniu.Http;
+using Qiniu.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Qiniu.Pili
+{
+    /// <summary>
+    /// 直播云服务端
+    /// </summary>
+    public class PiliManager
+    {
+        private const string PILI_API_HOST = "http://pili.qiniuapi.com";
+        private Auth _auth;
+        private HttpManager _httpManager;
+        private readonly string _hub;
+        private readonly string _encodedStreamTitle;
+
+        public PiliManager(Mac mac, string hub, string streamTitle)
+        {
+            _auth = new Auth(mac);
+            _httpManager = new HttpManager();
+            _hub = hub;
+            _encodedStreamTitle = Base64.UrlSafeBase64Encode(streamTitle);
+        }
+
+        private string saveAsEntry()
+        {
+            return string.Format("{0}/v2/hubs/{1}/streams/{2}/saveas", PILI_API_HOST, _hub, _encodedStreamTitle);
+        }
+
+        /// <summary>
+        /// 录制直播回放
+        /// </summary>
+        /// <param name="fname">保存的文件名</param>
+        /// <param name="start">要保存的直播的起始时间</param>
+        /// <param name="end">要保存的直播的结束时间</param>
+        /// <param name="format">保存的文件格式</param>
+        /// <param name="pipeline">数据处理的私有队列</param>
+        /// <param name="notify">保存成功回调通知地址</param>
+        /// <param name="expireDays">更改ts文件的过期时间</param>
+        /// <returns></returns>
+        public SaveAsResult SaveAs(string fname = "", long start = 0, long end = 0, string format = "", string pipeline = "", string notify = "", int expireDays = 0)
+        {
+            SaveAsRequest request = new SaveAsRequest(fname, start, end, format, pipeline, notify, expireDays);
+
+            SaveAsResult result = new SaveAsResult();
+
+            try
+            {
+                string url = saveAsEntry();
+                string body = request.ToJsonStr();
+                string token = _auth.CreateStreamManageToken(url, body);
+
+                HttpResult hr = _httpManager.PostJson(url, body, token);
+                result.Shadow(hr);
+            }
+            catch (Exception ex)
+            {
+                StringBuilder sb = new StringBuilder();
+                sb.AppendFormat("[{0}] [saveas] Error:  ", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
+                Exception e = ex;
+                while (e != null)
+                {
+                    sb.Append(e.Message + " ");
+                    e = e.InnerException;
+                }
+                sb.AppendLine();
+
+                result.RefCode = (int)HttpCode.INVALID_ARGUMENT;
+                result.RefText += sb.ToString();
+            }
+
+            return result;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Qiniu/Pili/SaveAsInfo.cs b/src/Qiniu/Pili/SaveAsInfo.cs
new file mode 100644
index 00000000..a5dd4bd4
--- /dev/null
+++ b/src/Qiniu/Pili/SaveAsInfo.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Qiniu.Pili
+{
+    /// <summary>
+    /// 录制直播回放-消息内容结果
+    /// </summary>
+    public class SaveAsInfo
+    {
+        /// <summary>
+        /// 代码 含义 说明
+        /// 200	success	成功(OK)
+        /// 612	stream not found    
+        /// 619	no data 没有直播数据
+        /// </summary>
+        public int Code { get; set; }
+
+        /// <summary>
+        /// 错误消息(状态码非OK时)
+        /// </summary>
+        public string Error { get; set; }
+
+        /// <summary>
+        /// 保存后在存储空间里的文件名
+        /// </summary>
+        public string FName { get; set; }
+
+        /// <summary>
+        /// 持久化异步处理任务ID,异步模式才会返回该字段,可以通过该字段查询转码进度
+        /// </summary>
+        public string PersistentID { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/src/Qiniu/Pili/SaveAsRequest.cs b/src/Qiniu/Pili/SaveAsRequest.cs
new file mode 100644
index 00000000..bd116f77
--- /dev/null
+++ b/src/Qiniu/Pili/SaveAsRequest.cs
@@ -0,0 +1,94 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Qiniu.Pili
+{
+    /// <summary>
+    /// 录制直播回放-请求
+    /// </summary>
+    public class SaveAsRequest
+    {
+        /// <summary>
+        /// 保存的文件名,不指定系统会随机生成
+        /// </summary>
+        [JsonProperty("fname")]
+        public string FileName { get; set; }
+        /// <summary>
+        /// 整数,Unix 时间戳,要保存的直播的起始时间,不指定或 0 值表示从第一次直播开始
+        /// </summary>
+        [JsonProperty("start")]
+        public long StartTimestamp { get; set; }
+        /// <summary>
+        /// 整数,Unix 时间戳,要保存的直播的结束时间,不指定或 0 值表示当前时间
+        /// </summary>
+        [JsonProperty("end")]
+        public long EndTimestamp { get; set; }
+        /// <summary>
+        /// 保存的文件格式,默认为m3u8,如果指定其他格式,则保存动作为异步模式。详细信息可以参考 转码 的api
+        /// </summary>
+        [JsonProperty("format")]
+        public string Format { get; set; }
+        /// <summary>
+        /// 异步模式时,数据处理的私有队列,不指定则使用公共队列
+        /// </summary>
+        [JsonProperty("pipeline")]
+        public string Pipeline { get; set; }
+        /// <summary>
+        /// 异步模式时,保存成功回调通知地址,不指定则不通知
+        /// </summary>
+        [JsonProperty("notify")]
+        public string Notify { get; set; }
+        /// <summary>
+        /// 更改ts文件的过期时间,默认为永久保存。-1 表示不更改ts文件的生命周期,正值表示修改ts文件的生命周期为expireDays
+        /// </summary>
+        [JsonProperty("expireDays")]
+        public int ExpireDays { get; set; }
+
+        /// <summary>
+        /// 初始化(所有成员为空,需要后续赋值)
+        /// </summary>
+        public SaveAsRequest()
+        {
+            FileName = "";
+            StartTimestamp = 0;
+            EndTimestamp = 0;
+            Format = "";
+            Pipeline = "";
+            Notify = "";
+            ExpireDays = 0;
+        }
+
+        /// <summary>
+        /// 初始化所有成员
+        /// </summary>
+        /// <param name="fname">保存的文件名</param>
+        /// <param name="start">要保存的直播的起始时间</param>
+        /// <param name="end">要保存的直播的结束时间</param>
+        /// <param name="format">保存的文件格式</param>
+        /// <param name="pipeline">数据处理的私有队列</param>
+        /// <param name="notify">保存成功回调通知地址</param>
+        /// <param name="expireDays">更改ts文件的过期时间</param>
+        public SaveAsRequest(string fname, long start, long end, string format, string pipeline, string notify, int expireDays)
+        {
+            FileName = fname;
+            StartTimestamp = start;
+            EndTimestamp = end;
+            Format = format;
+            Pipeline = pipeline;
+            Notify = notify;
+            ExpireDays = expireDays;
+        }
+
+        /// <summary>
+        /// 转换到JSON字符串
+        /// </summary>
+        /// <returns>请求内容的JSON字符串</returns>
+        public string ToJsonStr()
+        {
+            return JsonConvert.SerializeObject(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Qiniu/Pili/SaveAsResult.cs b/src/Qiniu/Pili/SaveAsResult.cs
new file mode 100644
index 00000000..a5468f2c
--- /dev/null
+++ b/src/Qiniu/Pili/SaveAsResult.cs
@@ -0,0 +1,90 @@
+using Newtonsoft.Json;
+using Qiniu.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Qiniu.Pili
+{
+    /// <summary>
+    /// 录制直播回放-结果
+    /// </summary>
+    public class SaveAsResult : HttpResult
+    {
+        /// <summary>
+        /// 获取带宽信息
+        /// </summary>
+        public SaveAsInfo Result
+        {
+            get
+            {
+                SaveAsInfo info = null;
+                if ((Code == (int)HttpCode.OK) && (!string.IsNullOrEmpty(Text)))
+                {
+                    info = JsonConvert.DeserializeObject<SaveAsInfo>(Text);
+                }
+                return info;
+            }
+        }
+
+        /// <summary>
+        /// 转换为易读字符串格式
+        /// </summary>
+        /// <returns>便于打印和阅读的字符串</returns>
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+
+            sb.AppendFormat("code:{0}\n", Code);
+
+            sb.AppendLine();
+
+            if (Result != null)
+            {
+                sb.AppendLine("result:");
+                sb.AppendFormat("code:{0}\n", Result.Code);
+                if (!string.IsNullOrEmpty(Result.Error))
+                {
+                    sb.AppendFormat("error:{0}\n", Result.Error);
+                }
+                if (!string.IsNullOrEmpty(Result.FName))
+                {
+                    sb.AppendFormat("fname:{0}\n", Result.FName);
+                }
+                if (!string.IsNullOrEmpty(Result.PersistentID))
+                {
+                    sb.AppendFormat("persistentID:{0}\n", Result.PersistentID);
+                }
+            }
+            else
+            {
+                if (!string.IsNullOrEmpty(Text))
+                {
+                    sb.AppendLine("text:");
+                    sb.AppendLine(Text);
+                }
+            }
+            sb.AppendLine();
+
+            sb.AppendFormat("ref-code:{0}\n", RefCode);
+
+            if (!string.IsNullOrEmpty(RefText))
+            {
+                sb.AppendLine("ref-text:");
+                sb.AppendLine(RefText);
+            }
+
+            if (RefInfo != null)
+            {
+                sb.AppendFormat("ref-info:\n");
+                foreach (var d in RefInfo)
+                {
+                    sb.AppendLine(string.Format("{0}:{1}", d.Key, d.Value));
+                }
+            }
+
+            return sb.ToString();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Qiniu/Qiniu.csproj b/src/Qiniu/Qiniu.csproj
index 588c7313..9bd98845 100644
--- a/src/Qiniu/Qiniu.csproj
+++ b/src/Qiniu/Qiniu.csproj
@@ -79,8 +79,14 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Pili\PiliManager.cs" />
+    <Compile Include="Pili\SaveAsInfo.cs" />
+    <Compile Include="Pili\SaveAsRequest.cs" />
+    <Compile Include="Pili\SaveAsResult.cs" />
     <Compile Include="QiniuCSharpSDK.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="RTC\RoomTokenRequest.cs" />
+    <Compile Include="RTC\RTCManager.cs" />
     <Compile Include="Storage\Config.cs" />
     <Compile Include="Storage\FetchInfo.cs" />
     <Compile Include="Storage\FetchResult.cs" />
@@ -156,6 +162,7 @@
     <None Include="packages.config" />
     <None Include="QiniuCSharpSDK.snk" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PostBuildEvent>
diff --git a/src/Qiniu/RTC/RTCManager.cs b/src/Qiniu/RTC/RTCManager.cs
new file mode 100644
index 00000000..8e33424e
--- /dev/null
+++ b/src/Qiniu/RTC/RTCManager.cs
@@ -0,0 +1,37 @@
+using Qiniu.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Qiniu.RTC
+{
+    /// <summary>
+    /// 实时音视频服务端
+    /// </summary>
+    public class RTCManager
+    {
+        private const string RTC_API_HOST = "http://rtc.qiniuapi.com";
+        private Auth _auth;
+
+        public RTCManager(Mac mac)
+        {
+            _auth = new Auth(mac);
+        }
+
+        /// <summary>
+        /// RoomToken签发服务
+        /// </summary>
+        /// <param name="appId">房间所属账号的AppID</param>
+        /// <param name="roomName">房间名称</param>
+        /// <param name="userId">请求加入房间的用户ID</param>
+        /// <param name="expireAt">鉴权的有效时间</param>
+        /// <param name="permission">该用户的房间管理权限</param>
+        /// <returns>RoomToken</returns>
+        public string GetRoomToken(string appId, string roomName, string userId, long expireAt, string permission)
+        {
+            RoomTokenRequest request = new RoomTokenRequest(appId, roomName, userId, expireAt, permission);
+            return _auth.CreateUploadToken(request.ToJsonStr());
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Qiniu/RTC/RoomTokenRequest.cs b/src/Qiniu/RTC/RoomTokenRequest.cs
new file mode 100644
index 00000000..0bfcfce8
--- /dev/null
+++ b/src/Qiniu/RTC/RoomTokenRequest.cs
@@ -0,0 +1,78 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Qiniu.RTC
+{
+    /// <summary>
+    /// 房间管理凭证-请求
+    /// </summary>
+    public class RoomTokenRequest
+    {
+        /// <summary>
+        /// 房间所属账号的AppID
+        /// </summary>
+        [JsonProperty("appId")]
+        public string AppID { get; set; }
+        /// <summary>
+        /// 房间名称
+        /// </summary>
+        [JsonProperty("roomName")]
+        public string RoomName { get; set; }
+        /// <summary>
+        /// 请求加入房间的用户ID
+        /// </summary>
+        [JsonProperty("userId")]
+        public string UserID { get; set; }
+        /// <summary>
+        /// 鉴权的有效时间,传入以秒为单位的 64 位 Unix 绝对时间,token 将在该时间后失效
+        /// </summary>
+        [JsonProperty("expireAt")]
+        public long ExpireAt { get; set; }
+        /// <summary>
+        /// 该用户的房间管理权限,"admin" 或 "user"
+        /// </summary>
+        [JsonProperty("permission")]
+        public string Permission { get; set; }
+
+        /// <summary>
+        /// 初始化(所有成员为空,需要后续赋值)
+        /// </summary>
+        public RoomTokenRequest()
+        {
+            AppID = "";
+            RoomName = "";
+            UserID = "";
+            ExpireAt = 0;
+            Permission = "";
+        }
+
+        /// <summary>
+        /// 初始化所有成员
+        /// </summary>
+        /// <param name="appId">房间所属账号的AppID</param>
+        /// <param name="roomName">房间名称</param>
+        /// <param name="userId">请求加入房间的用户ID</param>
+        /// <param name="expireAt">鉴权的有效时间</param>
+        /// <param name="permission">该用户的房间管理权限</param>
+        public RoomTokenRequest(string appId, string roomName, string userId, long expireAt, string permission)
+        {
+            AppID = appId;
+            RoomName = roomName;
+            UserID = userId;
+            ExpireAt = expireAt;
+            Permission = permission;
+        }
+
+        /// <summary>
+        /// 转换到JSON字符串
+        /// </summary>
+        /// <returns>请求内容的JSON字符串</returns>
+        public string ToJsonStr()
+        {
+            return JsonConvert.SerializeObject(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Qiniu/Util/Auth.cs b/src/Qiniu/Util/Auth.cs
index 0fe4934f..4021ab4d 100644
--- a/src/Qiniu/Util/Auth.cs
+++ b/src/Qiniu/Util/Auth.cs
@@ -24,7 +24,7 @@ public Auth(Mac mac)
         /// <param name="url">请求的URL</param>
         /// <param name="body">请求的主体内容</param>
         /// <returns>生成的管理凭证</returns>
-        public string CreateManageToken(string url,byte[] body)
+        public string CreateManageToken(string url, byte[] body)
         {
             return string.Format("QBox {0}", signature.SignRequest(url, body));
         }
@@ -72,11 +72,12 @@ public string CreateStreamPublishToken(string path)
         /// <summary>
         /// 生成流管理凭证
         /// </summary>
-        /// <param name="data"></param>
-        /// <returns></returns>
-        public string CreateStreamManageToken(string data)
+        /// <param name="url">访问的URL</param>
+        /// <param name="data">请求的数据</param>
+        /// <returns>生成的流管理凭证</returns>
+        public string CreateStreamManageToken(string url, string data)
         {
-            return string.Format("Qiniu {0}", signature.SignWithData(data));
+            return string.Format("Qiniu {0}", signature.SignStreamManageRequest(url, data));
         }
 
         #region STATIC
@@ -137,7 +138,7 @@ public static string CreateDownloadToken(Mac mac, string url)
         /// <param name="mac">账号(密钥)</param>
         /// <param name="path">URL路径</param>
         /// <returns></returns>
-        public static string CreateStreamPublishToken(Mac mac,string path)
+        public static string CreateStreamPublishToken(Mac mac, string path)
         {
             Signature sx = new Signature(mac);
             return sx.Sign(path);
diff --git a/src/Qiniu/Util/Signature.cs b/src/Qiniu/Util/Signature.cs
index 37919a60..edb3c870 100644
--- a/src/Qiniu/Util/Signature.cs
+++ b/src/Qiniu/Util/Signature.cs
@@ -1,4 +1,5 @@
-using System;
+using Qiniu.Http;
+using System;
 using System.IO;
 #if WINDOWS_UWP
 using Windows.Security.Cryptography;
@@ -111,6 +112,34 @@ public string SignRequest(string url, byte[] body)
             }
         }
 
+        /// <summary>
+        /// 直播流管理请求签名
+        /// </summary>
+        /// <param name="url">请求目标的URL</param>
+        /// <param name="body">请求的主体数据</param>
+        /// <returns>直播流管理请求签名</returns>
+        public string SignStreamManageRequest(string url, string body)
+        {
+            string data = "POST ";
+
+            Uri u = new Uri(url);
+            string pathAndQuery = u.PathAndQuery;
+
+            data += pathAndQuery;
+            data += string.Format("\nHost: {0}", u.Host);
+            data += string.Format("\nContent-Type: {0}",ContentType.APPLICATION_JSON);
+            data += "\n\n";
+            if (!string.IsNullOrWhiteSpace(body))
+            {
+                data += body;
+            }
+
+            HMACSHA1 hmac = new HMACSHA1(Encoding.UTF8.GetBytes(mac.SecretKey));
+            byte[] digest = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
+            string digestBase64 = Base64.UrlSafeBase64Encode(digest);
+            return string.Format("{0}:{1}", mac.AccessKey, digestBase64);
+        }
+
         /// <summary>
         /// HTTP请求签名
         /// </summary>