其实严格来讲,这个实现并非真正意义上的视频通信,既不是P2P的,也没有很高的性能,因为基本上是两个客户端同时往服务器上传递视频信息,然后由服务器进行中转到对方。
重点在于两点
- IIS根目录下放clientaccesspolicy.xml文件
- 注意服务中定义数据量大小2147483646,否则有可能传递不了
这边是单向的客户端定时向服务器传递带聊天标识的数据流:
代码
[DataContract]
public class UserVideo
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public string PartnerName { set; get; }
[DataMember]
public byte[] VideoByte { set; get; }
}
public class UserVideo
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public string PartnerName { set; get; }
[DataMember]
public byte[] VideoByte { set; get; }
}
服务契约只有两个,一个是用来存储视频流,一个是用来提供视频流的
代码
[ServiceContract]
public interface IChatService
{
[OperationContract]
void SendVideo(UserVideo userVideo);
[OperationContract]
List<UserVideo> GetVideos(string userName,string partnerName);
}
public interface IChatService
{
[OperationContract]
void SendVideo(UserVideo userVideo);
[OperationContract]
List<UserVideo> GetVideos(string userName,string partnerName);
}
实现也很简单就是往一个静态的List中添加对象
代码
public class ChatService : IChatService
{
private static List<UserVideo> listVideos = new List<UserVideo>();
public void SendVideo(UserVideo userVideo)
{
listVideos.Add(userVideo);
}
public List<UserVideo> GetVideos(string userName,string partnerName)
{
var list = listVideos.Where(m => m.UserName == userName && m.PartnerName == partnerName).ToList();
listVideos.RemoveAll(m => m.PartnerName == partnerName && m.UserName == userName);
return list;
}
}
{
private static List<UserVideo> listVideos = new List<UserVideo>();
public void SendVideo(UserVideo userVideo)
{
listVideos.Add(userVideo);
}
public List<UserVideo> GetVideos(string userName,string partnerName)
{
var list = listVideos.Where(m => m.UserName == userName && m.PartnerName == partnerName).ToList();
listVideos.RemoveAll(m => m.PartnerName == partnerName && m.UserName == userName);
return list;
}
}
接下来是host方法
代码
public class MyHost
{
static ServiceHost host = null;
public static void Open()
{
host = new ServiceHost(typeof(ChatService));
host.Open();
}
public static void Close()
{
if (host != null && host.State == CommunicationState.Opened)
{
host.Close();
}
host = null;
}
}
{
static ServiceHost host = null;
public static void Open()
{
host = new ServiceHost(typeof(ChatService));
host.Open();
}
public static void Close()
{
if (host != null && host.State == CommunicationState.Opened)
{
host.Close();
}
host = null;
}
}
最后是启动服务进行监听
代码
public class Program
{
static void Main(string[] args)
{
MyHost.Open();
System.Console.WriteLine("服务已经启动... 敲任意键停止服务");
System.Console.ReadLine();
MyHost.Close();
}
}
客户端方法:
开始视频播放
this.btnStartVideo.Click += (o, ev) =>
{
if (source != null)
{
source.Stop();
source.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
VideoBrush vBrush = new VideoBrush();
vBrush.SetSource(source);
this.rectangleUser.Fill = vBrush;
if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
{
source.Start();
}
}
};
向服务器发送数据流
this.btnSendVideo.Click += (o, ev) =>
{
timerForSend = new System.Windows.Threading.DispatcherTimer();
timerForSend.Interval = new TimeSpan(0, 0, 0, 0, 150);
timerForSend.Tick += (o1, e1) => {
proxy = new ChatServiceClient();
WriteableBitmap bmp = new WriteableBitmap(this.rectangleUser, null);
MemoryStream ms = new MemoryStream();
EncodeJpeg(bmp, ms);
UserVideo userVideo = new UserVideo();
userVideo.PartnerName = this.Partner;
userVideo.UserName = this.User;
userVideo.VideoByte = ms.GetBuffer();
proxy.SendVideoCompleted += (o2, e2) => { };
proxy.SendVideoAsync(userVideo);
};
timerForSend.Start();
};
{
static void Main(string[] args)
{
MyHost.Open();
System.Console.WriteLine("服务已经启动... 敲任意键停止服务");
System.Console.ReadLine();
MyHost.Close();
}
}
客户端方法:
开始视频播放
this.btnStartVideo.Click += (o, ev) =>
{
if (source != null)
{
source.Stop();
source.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
VideoBrush vBrush = new VideoBrush();
vBrush.SetSource(source);
this.rectangleUser.Fill = vBrush;
if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
{
source.Start();
}
}
};
向服务器发送数据流
this.btnSendVideo.Click += (o, ev) =>
{
timerForSend = new System.Windows.Threading.DispatcherTimer();
timerForSend.Interval = new TimeSpan(0, 0, 0, 0, 150);
timerForSend.Tick += (o1, e1) => {
proxy = new ChatServiceClient();
WriteableBitmap bmp = new WriteableBitmap(this.rectangleUser, null);
MemoryStream ms = new MemoryStream();
EncodeJpeg(bmp, ms);
UserVideo userVideo = new UserVideo();
userVideo.PartnerName = this.Partner;
userVideo.UserName = this.User;
userVideo.VideoByte = ms.GetBuffer();
proxy.SendVideoCompleted += (o2, e2) => { };
proxy.SendVideoAsync(userVideo);
};
timerForSend.Start();
};
从服务期上取得数据流
代码
void ReceiveVideo()
{
timerForReceive = new System.Windows.Threading.DispatcherTimer();
timerForReceive.Interval = new TimeSpan(0, 0, 0, 0, 100);
timerForReceive.Tick += (o, e) => {
proxy = new ChatServiceClient();
proxy.GetVideosCompleted += (se, ev) =>
{
if (ev.Error == null)
{
foreach (ChatService.UserVideo video in ev.Result)
{
this.imagePartner.Dispatcher.BeginInvoke(() => {
MemoryStream ms = new MemoryStream(video.VideoByte);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(ms);
imagePartner.Source = bitmap;
ms.Close();
});
}
}
};
proxy.GetVideosAsync(User, Partner);
};
timerForReceive.Start();
}
{
timerForReceive = new System.Windows.Threading.DispatcherTimer();
timerForReceive.Interval = new TimeSpan(0, 0, 0, 0, 100);
timerForReceive.Tick += (o, e) => {
proxy = new ChatServiceClient();
proxy.GetVideosCompleted += (se, ev) =>
{
if (ev.Error == null)
{
foreach (ChatService.UserVideo video in ev.Result)
{
this.imagePartner.Dispatcher.BeginInvoke(() => {
MemoryStream ms = new MemoryStream(video.VideoByte);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(ms);
imagePartner.Source = bitmap;
ms.Close();
});
}
}
};
proxy.GetVideosAsync(User, Partner);
};
timerForReceive.Start();
}
单工模式的缺点显而易见,请求--》答复比较耗时,我们下一步将会改造成双工模式的tcp通信。
本文转自wengyuli 51CTO博客,原文链接:http://blog.51cto.com/wengyuli/587192,如需转载请自行联系原作者