Android平台一对一音视频通话方案对比:WebRTC VS RTMP VS RTSP

一对一音视频通话使用场景

一对一音视频通话都需要稳定、清晰和流畅,以确保良好的用户体验,常用的使用场景如下:

  1. 社交应用:社交应用是一种常见的使用场景,用户可以通过音视频通话进行面对面的交流;
  2. 在线教育:老师和学生可以通过音视频通话功能进行实时互动,提高教学效率;
  3. 远程协助:在某些工作场景下,比如应急指挥项目,需要通过音视频通话功能进行远程协助,进行技术支持、维修服务等;
  4. 视频会议:一对一的音视频通话是视频会议非常重要的一部分,用于两个参会者之间的沟通,当然也可以合流输出;
  5. 语音通话:使用语音通话,如在行车过程中,此时语音通话就是一个很好的选择。

一对一音视频通话技术方案

WebRTC方案

在Android平台上实现一对一音视频通话,你可以使用WebRTC,WebRTC提供了实时音视频通话的功能。以下是一个简单的步骤说明如何实现:

  1. 设置环境:首先,你需要在你的开发环境中安装Android Studio,并且配置好必要的SDK;
  2. 添加依赖:在你的项目中,你需要添加WebRTC的库。在你的build.gradle文件中添加如下依赖;
  3. 实现音视频捕获:你需要实现音视频的捕获。在Java中,你可以使用AudioRecord和VideoCapturer类来实现;
  4. 创建PeerConnection:创建PeerConnection对象,这个对象会用于音视频的编解码和网络传输;
  5. 显示本地音视频流:使用MediaStream.VideoTrack和MediaStream.AudioTrack将捕获的音视频流添加到PeerConnection中,然后通过VideoRenderer和AudioRenderer显示出来;
  6. 创建并发送offer:创建并发送一个offer,这个offer包含了你的音视频通道信息以及你愿意接受的连接参数;
  7. 接收并解析offer:在另一端,接收到offer后,解析出音视频通道信息以及连接参数,然后创建并返回一个answer;
  8. 接收answer:在本地,接收到answer后,解析出音视频通道信息以及连接参数,然后创建并启动对应的通道。

RTMP方案

RTMP是一种基于TCP的流媒体协议,主要用于视频直播。它提供了实时传输音频和视频的功能,可以用于一对一或一对多的场景,RTMP可用于内网或公网环境下,缺点是需要单独部署RTMP Server,数据通过RTMP Server中转,配合低延迟的RTMP Player,互动可以很轻松的在毫秒级。

demo为例,RTMP推送的代码如下:

class ButtonPushStartListener implements OnClickListener { public void onClick(View v) { if (isPushingRtmp) { stopPush(); btnPushStartStop.setText("推送RTMP"); isPushingRtmp = false; return; } Log.i(PUSH_TAG, "onClick start push rtmp.."); if (libPublisher == null) return; InitPusherAndSetConfig(); Log.i(PUSH_TAG, "videoWidth: " pushVideoWidth " videoHeight: " pushVideoHeight " pushType:" pushType); if ( libPublisher.SmartPublisherSetURL(publisherHandle, publishURL) != 0 ) { Log.e(PUSH_TAG, "Failed to set rtmp pusher URL.."); } int startRet = libPublisher.SmartPublisherStartPublisher(publisherHandle); if (startRet != 0) { isPushingRtmp = false; Log.e(TAG, "Failed to start push stream.."); return; } CheckInitAudioRecorder(); btnPushStartStop.setText("停止推送 "); isPushingRtmp = true; };

停止RTMP推送:

//停止rtmp推送private void stopPush() { if(!isPushingRtmp) { return; } if ( !isrtspPublisherRunning) { if (audioRecord_ != null) { Log.i(TAG, "stopPush, call audioRecord_.StopRecording.."); audioRecord_.Stop(); if (audioRecordCallback_ != null) { audioRecord_.RemoveCallback(audioRecordCallback_); audioRecordCallback_ = null; } audioRecord_ = null; } } if (libpublisher != null) { libPublisher.SmartPublisherStopPublisher(publisherHandle); } if (!isRTSPPublisherRunning) { if (publisherHandle != 0) { if (libPublisher != null) { libPublisher.SmartPublisherClose(publisherHandle); publisherHandle = 0; } } }}

RTMP播放:

btnPlaybackStartStopPlayback.setOnClickListener(new Button.OnClickListener() { // @Override public void onClick(View v) { if(isPlaybackViewStarted) { btnPlaybackStartStopPlayback.setText("开始播放 "); if ( playerHandle != 0 ) { libPlayer.SmartPlayerStopPlay(playerHandle); libPlayer.SmartPlayerClose(playerHandle); playerHandle = 0; } isPlaybackViewStarted = false; } else { Log.i(PLAY_TAG, "Start playback stream "); playerHandle = libPlayer.SmartPlayerOpen(curContext); if(playerHandle == 0) { Log.e(PLAY_TAG, "sur faceHandle with nil.."); return; } libPlayer.SetSmartPlayerEventCallbackV2(playerHandle, new EventHandePlayerV2()); libPlayer.SmartPlayerSetSur face(playerHandle, playerSur faceView); //if set the second param with null, it means it will playback audio only.. libPlayer.SmartPlayerSetRenderScaleMode(playerHandle, 1); libPlayer.SmartPlayerSetExternalAudioOutput(playerHandle, new PlayerExternalPcmOutput()); libPlayer.SmartPlayerSetAudioOutputType(playerHandle, 1); libPlayer.SmartPlayerSetBuffer(playerHandle, playbackBuffer); libPlayer.SmartPlayerSetFastStartup(playerHandle, isPlaybackFastStartup?1:0); if ( isPlaybackMute ) { libPlayer.SmartPlayerSetMute(playerHandle, isPlaybackMute?1:0); } if (isPlaybackHardwareDecoder) { int isSupportHevcHwDecoder = libPlayer.SetSmartPlayerVideoHevcHWDecoder(playerHandle,1); int isSupportH264HwDecoder = libPlayer .SetSmartPlayerVideoHWDecoder(playerHandle,1); Log.i(TAG, "isSupportH264HwDecoder: " isSupportH264HwDecoder ", isSupportHevcHwDecoder: " isSupportHevcHwDecoder); } libPlayer.SmartPlayerSetAudioVolume(playerHandle, curAudioVolume); libPlayer.SmartPlayerSetUrl(playerHandle, playbackUrl); int iPlaybackRet = libPlayer.SmartPlayerStartPlay(playerHandle); if( iPlaybackRet != 0 ) { libPlayer.SmartPlayerClose(playerHandle); playerHandle = 0; Log.e(PLAY_TAG, "StartPlayback strem failed.."); return; } btnPlaybackStartStopPlayback.setText("停止播放 "); btnPlaybackPopInputUrl.setEnabled(false); btnPlaybackHardwareDecoder.setEnabled(false); btnPlaybackSetPlayBuffer.setEnabled(false); btnPlaybackFastStartup.setEnabled(false); isPlaybackViewStarted = true; Log.i(PLAY_TAG, "Start playback stream--"); } } });

本文福利, 免费领取C 音视频学习资料包 学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs),有需要的可以进企鹅裙927239107领取哦~

轻量级RTSP服务 RTSP播放方案

纯内网环境下,两个终端可同时开启轻量级RTSP服务,然后相互拉取对方回调上来的RTSP URL,通过回音消除等,实现智能化场景的一对一音视频互动,不然智能门禁等场景,均可使用,实测延迟毫秒级,不影响互动体验,效果非常好:

对应的代码如下:

//Author: daniusdk.com //启动/停止RTSP服务 class ButtonRtspServiceListener implements OnClickListener { public void onClick(View v) { if (isRTSPServiceRunning) { stopRtspService(); btnRtspService.setText("启动RTSP服务"); btnRtspPublisher.setEnabled(false); isRTSPServiceRunning = false; return; } Log.i(TAG, "onClick start rtsp service.."); rtsp_handle_ = libPublisher.OpenRtspServer(0); if (rtsp_handle_ == 0) { Log.e(TAG, "创建rtsp server实例失败! 请检查SDK有效性"); } else { int port = 8554; if (libPublisher.SetRtspServerPort(rtsp_handle_, port) != 0) { libPublisher.CloseRtspServer(rtsp_handle_); rtsp_handle_ = 0; Log.e(TAG, "创建rtsp server端口失败! 请检查端口是否重复或者端口不在范围内!"); } //String user_name = "admin"; //String password = "12345"; //libPublisher.SetRtspServerUserNamePassword(rtsp_handle_, user_name, password); if (libPublisher.StartRtspServer(rtsp_handle_, 0) == 0) { Log.i(TAG, "启动rtsp server 成功!"); } else { libPublisher.CloseRtspServer(rtsp_handle_); rtsp_handle_ = 0; Log.e(TAG, "启动rtsp server失败! 请检查设置的端口是否被占用!"); } btnRtspService.setText("停止RTSP服务"); btnRtspPublisher.setEnabled(true); isRTSPServiceRunning = true; } } }

发布RTSP流:

//发布/停止RTSP流 class ButtonRtspPublisherListener implements OnClickListener { public void onClick(View v) { if (isRTSPPublisherRunning) { stopRtspPublisher(); if (!isPushingRtmp) { ConfigControlEnable(true); } btnRtspPublisher.setText("发布RTSP流"); btnGetRtspSessionNumbers.setEnabled(false); btnRtspService.setEnabled(true); isRTSPPublisherRunning = false; return; } Log.i(TAG, "onClick start rtsp publisher.."); if (!isPushingRtmp) { InitPusherAndSetConfig(); } if (publisherHandle == 0) { Log.e(TAG, "Start rtsp publisher, publisherHandle is null.."); return; } String rtsp_stream_name = "stream1"; libPublisher.SetRtspStreamName(publisherHandle, rtsp_stream_name); libPublisher.ClearRtspStreamServer(publisherHandle); libPublisher.AddRtspStreamServer(publisherHandle, rtsp_handle_, 0); if (libPublisher.StartRtspStream(publisherHandle, 0) != 0) { Log.e(TAG, "调用发布rtsp流接口失败!"); return; } if (!isPushingRtmp) { if (pushType == 0 || pushType == 1) { CheckInitAudioRecorder(); //enable pure video publisher.. } ConfigControlEnable(false); } startLayerPostThread(); btnRtspPublisher.setText("停止RTSP流"); btnGetRtspSessionNumbers.setEnabled(true); btnRtspService.setEnabled(false); isRTSPPublisherRunning = true; } }

获取RTSP流会话链接数:

//当前RTSP会话数弹出框 private void PopRtspSessionNumberDialog(int session_numbers) { final EditText inputUrlTxt = new EditText(this); inputUrlTxt.setFocusable(true); inputUrlTxt.setEnabled(false); String session_numbers_tag = "RTSP服务当前客户会话数: " session_numbers; inputUrlTxt.setText(session_numbers_tag); AlertDialog.Builder builderUrl = new AlertDialog.Builder(this); builderUrl .setTitle("内置RTSP服务") .setView(inputUrlTxt).setNegativeButton("确定", null); builderUrl.show(); } //获取RTSP会话数 class ButtonGetRtspSessionNumbersListener implements OnClickListener { public void onClick(View v) { if (libPublisher != null && rtsp_handle_ != 0) { int session_numbers = libPublisher.GetRtspServerClientSessionNumbers(rtsp_handle_); Log.i(TAG, "GetRtspSessionNumbers: " session_numbers); PopRtspSessionNumberDialog(session_numbers); } } }

播放RTSP不再赘述,和播放RTMP一样,只是URL类型不一样,需要注意的是,不管走RTMP还是RTSP,都需要开启回音消除。

技术总结

Android平台一对一互动,纯内网环境下,不部署单独的流媒体服务器,走轻量级RTSP服务真的非常方便,如果需要扩展到公网业务,建议可以考虑RTMP,如果有很好的开发能力,也可以考虑WebRTC,具体根据实际场景选择即可。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

(0)
上一篇 2024年5月6日 下午3:12
下一篇 2024年5月6日 下午3:24

相关推荐

  • 如何做好施工企业标准化党建工作(如何做好施工企业标准化党建工作心得体会)

    摘编自杂志文章《如何做好施工企业标准化党建工作》,原文刊于《现代商贸工业》(国内统一刊号:CN42-1687/T;国际标准刊号:ISSN 1672-3198)2021年1期。【本文…

    科研百科 2023年1月13日
    187
  • 化工暑期科研项目申报书

    化工暑期科研项目申报书 尊敬的评审专家: 我们荣幸地向您申报我们的化工暑期科研项目。该项目旨在探索新的合成方法,以提高化工产品的产量和质量。 该项目的主要目标是研究一种高效,经济,…

    科研百科 2025年4月1日
    1
  • 郴州,“党建+就业”端稳就业“饭碗”(xs贵还是x贵)

    郴州人社协理员近距离服务群众就业时的场景。郴州市人社局供图 李秉钧 李 鹏 近日,郴州市人社局有关负责人一行,到北湖区人民路街道北湖路社区专题调研。该社区创新基层治理“党建 ”模式…

    科研百科 2024年7月6日
    73
  • 如何管理好农村基层党员(如何管理好农村基层党员工作)

    党员的教育管理是党建工作中最基本也是最重要的工作。伴随着改革开放经济社会发展,农村党员的流动性增大,农村党员管理也成为当前党建工作新的课题。 如今,农村党员管理难度大,农村党员老龄…

    科研百科 2023年1月31日
    257
  • 怎样写科研项目

    怎样写科研项目 科研项目是科学家们进行学术研究的重要工具,也是推动科学技术发展的重要力量。在写科研项目时,需要注意以下几点: 1. 项目标题要简洁明了,能够准确地概括项目的主要内容…

    科研百科 2025年3月21日
    1
  • 项目管理工具 有哪些

    项目管理工具有哪些 项目管理是组织中非常重要的一部分,通过使用项目管理工具,可以更高效地管理项目,提高项目进展和质量。以下是一些常用的项目管理工具: 1. Microsoft Pr…

    科研百科 2024年9月24日
    25
  • 手机电脑协同办公

    手机电脑协同办公:现代办公的新方式 随着科技的不断发展,手机电脑协同办公已经成为了现代办公的新方式。无论是在家中、办公室还是旅途中,我们可以通过手机和电脑进行信息的传输和协作,实现…

    科研百科 2024年8月28日
    27
  • 合同管理监理查询

    合同管理监理查询是一个非常重要的工作,涉及到企业的运营和管理。合同管理监理查询可以帮助企业确保合同的有效性和合规性,同时也可以帮助企业减少风险和成本。 合同管理监理查询的重要性 合…

    科研百科 2024年5月25日
    72
  • 陕钢龙钢炼铁厂党委组织召开“岗位廉洁风险防控机制建设工作知识”培训会

    陕西网(通讯员 梁曦 )4月10日,陕钢集团龙钢公司炼铁厂党委为进一步深化、巩固和提升廉政风险防控机制建设工作,在分厂第一会议室组织召开了“岗位廉洁风险防控机制建设工作知识”培训会…

    科研百科 2023年6月22日
    133
  • 图论科研项目 申报书

    科研项目申报书 项目名称: 基于图神经网络的智能推荐系统 项目背景: 随着互联网的普及,人们获取信息的方式发生了翻天覆地的变化。传统的搜索引擎已经不能满足人们对于信息的快速、精准的…

    科研百科 2025年3月21日
    1