- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在一些有人际互动的手机APP中,增加语音视频聊天功能是一个常见的需求。而现在,更进一步,在某些场景下,我们需要能将自己的手机屏幕分享给他人,或者是观看他人的手机屏幕。那么,这些常见的功能是如何实现的了? 我为此专门写了一个安卓版的Demo,并将源码放出来供大家参考,希望对大家有所帮助.
(1)每个登录的用户都可向其他任意在线用户发送视频聊天请求.
(2)当收到来自其他在线用户的视频聊天邀请时,可接受或拒绝对方的请求.
(3)当接受其他在线用户的视频聊天邀请时,就启动视频聊天.
(1)每个登录的用户都可向其他任意在线用户发送屏幕分享请求;当对方未响应时,可主动取消屏幕分享请求.
(2)当收到来自其他在线用户请求屏幕分享时,可接受或拒绝对方的请求.
(3)当发送方收到其他在线用户同意屏幕分享时,即可观看其屏幕 。
(4)被控端和主控端都可主动断开屏幕分享.
Android Studio 4.0 。
JAVA 。
Netty 、OMCS 。
类似视频聊天或屏幕分享这样的功能,一般是C/S架构的。在这种应用中,服务端相对简单,其主要是在客户端之间转发消息。本Demo提供了一个非常简易的C#服务端(开发环境:VS 2022),直接运行起来即可。下面我们将主要介绍安卓端的实现。 大家可以从文末下载安卓端的源码,在阅读本文时对照源码,就会更清楚些。 首先,我们先要确定客户端之间相互通信的消息类型.
public class InformationTypes {
/// <summary>
/// 视频请求 0
/// </summary>
public static final int VideoRequest = 0;
/// <summary>
/// 回复视频请求的结果 1
/// </summary>
public static final int VideoResult = 1;
/// <summary>
/// 通知对方 挂断 视频连接 2
/// </summary>
public static final int CloseVideo = 2;
/// <summary>
/// 通知好友 网络原因,导致 视频中断 3
/// </summary>
public static final int NetReasonCloseVideo = 3;
/// <summary>
/// 通知对方(忙线中) 挂断 视频连接 4
/// </summary>
public static final int BusyLine = 4;
/// <summary>
/// 屏幕分享请求 5
/// </summary>
public static final int DesktopRequest = 5;
/// <summary>
/// 回复屏幕分享请求的结果 6
/// </summary>
public static final int DesktopResult = 6;
/// <summary>
/// 主动取消屏幕分享请求
/// </summary>
public static final int CancelDesktop = 7;
/// <summary>
/// 对方(主人端)主动断开屏幕分享
/// </summary>
public static final int OwnerCloseDesktop = 8;
/// <summary>
/// 客人端断开屏幕分享
/// </summary>
public static final int GuestCloseDesktop = 9;
}
这里我们定义了为了实现第一部分“ 功能介绍 ”中的功能,所需要用到的消息类型.
在安卓上进行视频聊天和屏幕分享,APP需要向安卓系统申请3个权限:麦克风、摄像头、屏幕录制.
private void getPermission() {
List<PermissionItem> permissionItems = new ArrayList<PermissionItem>();
permissionItems.add(new PermissionItem(Manifest.permission.CAMERA, "相机", R.drawable.permission_ic_camera));
permissionItems.add(new PermissionItem(Manifest.permission.RECORD_AUDIO, "麦克风", R.drawable.permission_ic_micro_phone));
permissionItems.add(new PermissionItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "存储", R.drawable.permission_ic_storage));
permissionItems.add(new PermissionItem(Manifest.permission.READ_EXTERNAL_STORAGE, "", 0));
try {
HiPermission.create(LoginActivity.this)
.title("欢迎访问" + getString(R.string.app_name))
.permissions(permissionItems)
.checkMutiPermission(new PermissionCallback() {
String TAG = getString(R.string.app_name);
@Override
public void onClose() {
Log.i(TAG, "onClose");
}
@Override
public void onFinish() {
Log.i(TAG, "onFinish");
}
@Override
public void onDeny(String permission, int position) {
Log.i(TAG, "onDeny- permission:" + permission + " position:" + position);
}
@Override
public void onGuarantee(String permission, int position) {
Log.i(TAG, "onGuarantee");
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
当安卓手机首次进入该Demo时, 将弹窗提示获取设备权限:
注:若禁止了这两个权限,后续就无法进行正常的视频聊天了! 。
MultimediaManagerFactory.GetSingleton().setDesktopRecordActivity(MainActivity.this);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
MultimediaManagerFactory.GetSingleton().setDesktopRecordActivityResult(requestCode,resultCode,data);
}
当收到其他在线用户的屏幕分享请求并回复同意时,将弹窗获取屏幕权限:
注:若禁止该权限,后续对方就无法看到分享者的屏幕了.
当发起视频聊天时,将显示视频聊天窗口,并打开手机摄像头预览画面,然后向对方发送视频通话请求:
CameraSurfaceView2 myView = null;
MultimediaManagerFactory.GetSingleton().getAudioMessageController().dispose();
AndroidUtil.OpenSpeaker(this);
try {
MultimediaManagerFactory.GetSingleton().openCamera();
} catch (Exception e) {
e.printStackTrace();
}
this.tv_nick = (TextView) findViewById(R.id.tv_nick);
myView = (CameraSurfaceView2) findViewById(R.id.local_surface);
myView.setSurfaceEventLister(new CameraSurfaceView2.SurfaceEventLister() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
setShowPreviewHolder(surfaceHolder);
}
});
myView.setZOrderOnTop(true);
MultimediaManagerFactory.GetSingleton().setCameraDeviceIndex(1);//设置为前置摄像头
//设置摄像头打开成功回调函数
MultimediaManagerFactory.GetSingleton().setCameraOpenCallBack(this);
if (StringHelper.isNullOrEmpty(userId)) {
isSender = true;
//我向对方发起视频
userId = getIntent().getStringExtra(TalkingID);
if (StringHelper.isNullOrEmpty(userId)) {
tv_nick.setText("未知requestID");
} else {
ll_to_callLayout.setVisibility(View.VISIBLE);
coming_callLayout.setVisibility(View.GONE);
hangup.setVisibility(View.VISIBLE);
MainActivity.getInstance().sendMediaCommunicate(userId, CommunicateType.Request);
tv_tips.setText("正在等待对方接受邀请");
}
}
运行起来的UI截图如下所示:
当收到对方的视频聊天邀请时,将进入视频预览页面,显示视频邀请.
当点击“接听”或“挂断”按钮时,就会发送视频聊天回复消息:
//接听
answer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
MainActivity.getInstance().stopRingForCalling();
coming_callLayout.setVisibility(View.GONE);
ll_to_callLayout.setVisibility(View.VISIBLE);
openConnector();
MainActivity.getInstance().sendMediaCommunicate(userId, CommunicateType.Agree);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
//拒绝
refuse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
MainActivity.getInstance().sendMediaCommunicate(userId, CommunicateType.Reject);
MainActivity.getInstance().stopRingForCalling();
finish();
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
当对方回复同意时,自己和对方将相互连接到对方的麦克风和摄像头.
private void openConnector() {
try {
if (thread2 != null) {
thread2.interrupt();
}
hangup.setVisibility(View.VISIBLE);
switch_camera_layout.setVisibility(View.VISIBLE);
ll_top_container.setVisibility(View.INVISIBLE);
thread2 = new Thread(new Runnable() {
Override
public void run() {
//在这里关闭不能重新连接
cameraConnector = new CameraConnector();
cameraConnector.setOtherVideoPlayerSurfaceView(otherView);
cameraConnector.setConnectorEventListener(new IConnectorEventListener() {
@Override
public void connectEnded(ConnectResult connectResult) {
final String connectFailStr = MainActivity.getConnectFailStr(connectResult);
if (!StringHelper.isNullOrEmpty(connectFailStr)) {
mHandler.post(new Runnable() {
@Override
public void run() {
tv_camera_failure_cause.setText("摄像头:" + connectFailStr);
}
});
}
boolean isMobilePhone = cameraConnector.getOwnerMachineType() == MachineType.Android || cameraConnector.getOwnerMachineType() == MachineType.IOS;
cameraConnector.setVideoUniformScale(true, isMobilePhone); //false 表示小的那边留黑边,true表示裁剪大的那一边
}
@Override
public void disconnected(ConnectorDisconnectedType connectorDisconnectedType) {
}
});
cameraConnector.beginConnect(loginID);
microphoneConnector = new MicrophoneConnector();
microphoneConnector.setConnectorEventListener(new IConnectorEventListener() {
@Override
public void connectEnded(final ConnectResult connectResult) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (connectResult == ConnectResult.Succeed) {
startTimer(SystemClock.elapsedRealtime());
} else {
String connectFailStr = MainActivity.getConnectFailStr(connectResult);
tv_mic_failure_cause.setText("麦克风:" + connectFailStr);
}
}
});
}
@Override
public void disconnected(ConnectorDisconnectedType connectorDisconnectedType) {
}
});
microphoneConnector.beginConnect(loginID);
}
});
thread2.start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
当摄像头和麦克风都连接成功后,就可以正常视频聊天了.
屏幕分享功能的业务逻辑与视频聊天功能的业务逻辑是相似的,这里就不再赘述了,大家可以自行参看源码.
关于Demo的源码介绍就这么多了,接下来我们看如何将Demo运行起来.
解压 VideoChatMini.rar 后,进入解压目录,依次进入 VideoChatMini.Server -> bin -> debug 。 双击 Oraycn.Demos.VideoChatMini.Server.exe ,即可启动视频聊天服务端。服务端运行界面如下所示:
解压安卓端源码压缩包 VideoChatMini.Android.rar,解压后,使用 Android Studio 打开并编译,将生成的apk发送到手机安装.
我们可以用两部手机,启动并登录两个安卓客户端,登录的账号密码可以随便填。安卓端登录成功后,出现如下界面:
我们在 “对方ID” 输入框中填上对方的登录账号,就可以发起视频聊天邀请了。对应的界面截图在前面已经贴出来了。 对方同意视频邀请后,两个人就开启视频聊天了,运行效果如下所示:
Android 端: VideoChatMini.Android.rar 。
服务端 + PC 端: VideoChatMini.rar 。
在这里,我也给出了PC端的源码,PC端项目对应的目录是 VideoChatMini.ClientWPF。服务端和PC端都是 C# 开发的(开发环境是 VS2022),PC端UI使用的是WPF.
PC端和安卓端是可以互通的,也就是可以相互视频通话,以及观看屏幕/桌面.
希望这篇文章会对你有所帮助,谢谢.
最后此篇关于如何实现安卓屏幕分享及视频聊天?(源码)的文章就讲到这里了,如果你想了解更多关于如何实现安卓屏幕分享及视频聊天?(源码)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想知道 gmail 聊天如何允许用户连接到 AIM,然后像登录到 AIM 一样聊天。 做起来容易吗?怎么做到的? 有人知道任何类似的开源工具吗? 谢谢! 最佳答案 如果你在谈论编程,这里是源代码示例
大家好,我正在尝试制作一个游戏,两个主持人联系起来,他们将“掷硬币”,并确定谁先出局。我决定从基本代码开始。但是我真的没有主意。 Thread server2 = new Thread(new Ser
我已经创建了一个只有 1 个房间的聊天室、私有(private)消息、审核以及一切,现在一切都很好!当我测试聊天时,我意识到在聊天中输入的所有消息都会被保存,如果有很多人使用聊天,它很快就会占用 Fi
当用户键入内容并出现软键盘时,我必须保持聊天回收器 View 的当前项目可见。目前,它覆盖了聊天,我需要回收器 View 项目与键盘一起显示。 我在 list 中尝试了这些: -android:win
我有一个服务器客户端应用程序集。 (家庭作业) 到目前为止,我已经弄清楚如何让多个客户端连接到服务器并让服务器聚合客户端发送的消息,以及如何让服务器将客户端的消息发送回客户端并将其显示在聊天 Pane
如何从我的应用程序发送/接收 Facebook 聊天消息?它是用 .Net、C# 编写的。 最佳答案 如果你可以使用 C,你就可以使用 libpurple (GPL) 和 pidgin-faceboo
我正在使用启用的 Ajax-Wcf 服务开发 Asp.Net 聊天。这是一个非常简单的聊天引擎,其中消息对话框意味着一对一(单个用户),但是我不知道如何管理(以最佳方式)通知新消息可用性。例如,假设有
我的任务是通过服务器构建一个客户端到客户端的聊天程序。客户端 A 将向服务器发送一条消息,然后服务器将消息转发给客户端 B,反之亦然。所有这一切都将同时发生,直到其中一个将其关闭。我有以下程序。 服务
我创建了一个聊天,用户可以在其中输入文本的输入字段。当他输入文本并按下发送(或输入)时,文本位于输入字段上方。像这样: 我想要的:我希望输入字段位于页面底部。我使用 position: absolut
出于个人兴趣,我尝试定义一个模拟 AI,它基于他学到的信息和互联网搜索,以便提供比系统知道的更多的细节。 我举了一个 child 的例子,当他出生时他需要学习一切,他听到了很多然后提出了一些答案。他的
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 3年前关闭。 Improve this qu
我已经开始聊天了,但我已经将用户的 ID 硬编码到 Chat.php 中。 当他们登录站点时,我的登录名将他们的电子邮件设置为 session ( $_SESSION['email']=$email;
当用户点击像 Start a viber chat with us 这样的链接时,我试图找到一种方法来开始 viber 聊天。但到目前为止我没有找到正确的URI来做到这一点。例如,我知道我可以使用 s
我是 Javascript(纯 javascript)新手,我正在尝试创建一个执行以下操作的聊天 Controller 应用程序。 用户输入内容。 有人对我的知识库进行了后调用。 服务器响应消息。 目
已关闭。这个问题是 not about programming or software development 。目前不接受答案。 这个问题似乎不是关于 a specific programming
如果用户在 x 秒/分钟内处于非事件状态,我想结束聊天,以便我们的代理不必等待聊天自行关闭。我还想在结束聊天之前将标签附加到聊天中,以便我可以看到这是由于不活动造成的。 最佳答案 此内容归功于 j
我正在此网站中构建新网站,客户需要 24/7 实时客户支持。我想在网站上集成 Skype 聊天 聊天界面应该在客户端的网站上。 最佳答案 您可以通过在网站上放置 Skype 按钮来使用它。 http:
事实上,我只是开始积极练习 swing,以便我的理论知识能派上用场:) 我已经为聊天 GUI 实现做了很多工作,但最终遇到了一些问题。所以我决定从头开始重新设计聊天 GUI,但我需要为其选择正确的组件
已关闭。这个问题是 not about programming or software development 。目前不接受答案。 这个问题似乎不是关于 a specific programming
我正在尝试进行简单的聊天,其中连接到服务器的用户发送消息,其他用户接收消息。 这是我的 html: function setupEventSource()
我是一名优秀的程序员,十分优秀!