用腾讯即时通讯IM和实时音视频实现陪玩系统源码的语音通话功能

在陪玩系统源码中,用户之间主要的交流方式就是语音通话,实时互动性的语音通话能让人产生面对面交谈的感觉,所以在陪玩系统源码中,语音通话功能的开发非常重要,今天我们就一起来看看如何用腾讯即时通讯IM和实时音视频实现陪玩系统源码的语音通话功能吧。

大致分为以下几步:

  • 初步实现语音通话
  • 完善通话逻辑
  • 铃声震动实现、悬浮窗实现

初步实现陪玩系统源码的语音通话

1、集成SDK

  • 在模块的build.gradle中的 dependencies中添加
    dependencies {implementation 'com.tencent.liteav:LiteAVSDK_TRTC:latest.release'}
  • 在defaultCOnfig中,指定CPU架构
    defaultConfig {ndk {abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"}}
  • 配置权限
    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses- permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-feature android:name="android.hardware.camera" /><uses-feature android:name="android.hardware.camera.autofocus" />
  • 设置混淆
    -keep class com.tencent.** { *; }
  • 设置打包参数
   packagingOptions {pickFirst '**/libc++_shared.so'doNotStrip "*/armeabi/libYTCommon.so"doNotStrip "*/armeabi-v7a/libYTCommon.so"doNotStrip "*/x86/libYTCommon.so"doNotStrip "*/arm64-v8a/libYTCommon.so"}

2、实现通话

复制源码文件夹trtcaudiocalldemo 中的ui和model到项目中。这里看自己的需求进行选择,实现陪玩系统源码的语音通话,我们只需要TRTCAudioCallActivity.java文件
复制CallService 到项目中,这个Service主要负责处理接听电话的事务(接听电话需要进房需要查询用户信息,生成一个beingCallUserModel传入)
调用 TRTCAudioCallActivity.startCallSomeone(getContext(), mContactList);发起陪玩系统源码的语音通话,这里的mContactList 如果是单聊或者群聊只邀请一个人,只会有一个model,查询设置这个model的avatar、phone、userid、username、groupId即可。到此初步集成完毕,可以进行语音通话了。

完善陪玩系统源码通话逻辑

1、Android端的通话逻辑并不完善,让我们来看看它的问题

  • 不会发送结束消息,任何情况下的挂断都是发送 取消命令
  • 群通话远端用户离开房间不会触发通话挂断

问题所在:TRTCAuduiCallImpl中的hangup 在通话进行中或者发起人主动挂断的情况下只会发送取消通话命令
在这里插入图片描述
根据正常的打电话逻辑,A打给B,会有以下几种情况

  • 未通话:A取消,B拒绝,
  • 通话中:A挂断 ,B挂断

首先B拒绝,会在hangup方法中进入reject()方法中,发送一个拒绝的消息,这个我们不用处理;然后是A取消的情况,可以通过判断邀请列表的人,如果邀请列表的人大于0,这个时候挂断,那么一定是A取消;再是A挂断和B挂断,这里得区分一下在陪玩系统源码中是群聊通话,还是单聊通话,如果是单聊通话,那么A挂断 就是A判断房间中用户数未0,发送一个通话结束消息出去,同理B一样。如果是群聊中,那么就是最后一个退出房间的人判断,发送一个通话结束的消息出去。

所以在群聊和单聊中我们可以这样判断:

                    Log.d(TAG, "Hangup: " + mCurRoomUserSet + " " + mCurInvitedList + "  " + mIsInRoom);if (mIsInRoom) {if (isCollectionEmpty(mCurRoomUserSet)) {if (mCurInvitedList.size() > 0) {//取消sendModel("", CallModel.VIDEO_CALL_ACTION_SPONSOR_CANCEL);} else {//通话结束sendModel("", CallModel.VIDEO_CALL_ACTION_HANGUP);}}}stopCall();exitRoom();}

并且如果是群聊 ,需要在远端用户退出群主,并且群主里面没有用户的时候发送通话结束的消息即 在preExitRoom方法里面调用groupHangup方法,并且退房相关操作需要注释掉,因为groupHangup方法里面会对房间参数进行判断,需要发消息,然后退房。

当然发送消息并退房并不是陪玩系统源码中所有情况都适用,比如忙线,拒接、超时的时候,就只需要执行退房操作,所以在这些情况下不能调用groupHangup方法,只判断执行退房操作。

2、解析陪玩系统源码自定义消息

这个东西看需求,一般情况下,一次通话都会有两条消息,即一条发起通话消息,一条结束(拒绝、忙线、挂断、超时等情况)。

  private void buildVoiceCallView(ICustomMessageViewGroup parent, MessageInfo info, TRTCAudioCallImpl.CallModel data) {if (data.action == TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_DIALING) {// 把自定义消息view添加到TUIKit内部的父容器里View view = LayoutInflater.from(AndroidApplication.getInstance()).inflate(R.layout.dial_senc_call_message, null, false);parent.addMessageItemView(view);TextView tv = view.findViewById(R.id.tv_content);if (info.isSelf()) {tv.setText("您发起了语音通话");} else {tv.setText("对方发起了语音通话");}return;}// 把自定义消息view添加到TUIKit内部的父容器里View view = LayoutInflater.from(AndroidApplication.getInstance()).inflate(R.layout.dial_custom_message, null, false);parent.addMessageContentView(view);// 自定义消息view的实现,这里仅仅展示文本信息,并且实现超链接跳转TextView textView = view.findViewById(R.id.tv_dial_status);ImageView ivLeft = view.findViewById(R.id.iv_left);ImageView ivRight = view.findViewById(R.id.iv_right);if (info.isSelf()) {ivRight.setVisibility(View.VISIBLE);ivLeft.setVisibility(View.GONE);textView.setTextColor(getResources().getColor(R.color.white));} else {ivRight.setVisibility(View.GONE);ivLeft.setVisibility(View.VISIBLE);textView.setTextColor(getResources().getColor(R.color.color_333333));}String text;switch (data.action) {case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_SPONSOR_CANCEL:text = "已取消";break;case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_REJECT:text = "已拒绝";break;case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_SPONSOR_TIMEOUT:text = "无人接听";break;case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_HANGUP:if (data.duration == 0) {text = "通话结束";} else {text = "通话结束 " + TimeUtils.millis2StringByCorrect(data.duration * 1000, data.duration >= 60 * 60 ? "HH:mm:ss" : "mm:ss");}break;case TRTCAudioCallImpl.CallModel.VIDEO_CALL_ACTION_LINE_BUSY:text = "忙线中";break;default:text = "未知通话错误";break;}textView.setText(text);}

铃声震动实现、悬浮窗实现

1、铃声震动(呼叫和待接听响铃,接听和挂断停止响铃)

  • 陪玩系统源码呼叫方邀请页面响铃或震动,在showInvitingView()方法中添加
//开始呼叫响铃
if (mRingVibrateHelper != null) {    mRingVibrateHelper.initLocalCallRinging();}
  • 用户在陪玩系统源码中通话中停止响铃或震动,在showCallingView()方法中使用
//停止响铃if (mRingVibrateHelper != null) {    mRingVibrateHelper.stopRing();}
  • 陪玩系统源码接听方在,接听等待页面响铃或震动,在showWaitingResponseView()方法中使用
//响铃或者震动mRingVibrateHelper.initRemoteCallRinging();
  • 页面退出,停止响铃
 if (mRingVibrateHelper != null) {mRingVibrateHelper.stopRing();mRingVibrateHelper.releaseMediaPlayer();}

分享一下响铃震动帮助类TimRingVibrateHelper

/*** @author leary* 响铃震动帮助类*/
public class TimRingVibrateHelper {private static final String TAG = TimRingVibrateHelper.class.getSimpleName();/*** =============响铃 震动相关*/private MediaPlayer mMediaPlayer;private Vibrator mVibrator;private static TimRingVibrateHelper instance;public static TimRingVibrateHelper getInstance() {if (instance == null) {synchronized (TimRingVibrateHelper.class) {if (instance == null) {instance = new TimRingVibrateHelper();}}}return instance;}private TimRingVibrateHelper() {//铃声相关mMediaPlayer = new MediaPlayer();mMediaPlayer.setOnPreparedListener(mp -> {if (mp != null) {mp.setLooping(true);mp.start();}});}/*** ==============响铃、震动相关方法========================*/public void initLocalCallRinging() {try {AssetFileDescriptor assetFileDescriptor = AndroidApplication.getInstance().getResources().openRawResourceFd(R.raw.voip_outgoing_ring);mMediaPlayer.reset();mMediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());assetFileDescriptor.close();// 设置 MediaPlayer 播放的声音用途if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {AudioAttributes attributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build();mMediaPlayer.setAudioAttributes(attributes);} else {mMediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);}mMediaPlayer.prepareAsync();final AudioManager am = (AudioManager) AndroidApplication.getInstance().getSystemService(Context.AUDIO_SERVICE);if (am != null) {am.setSpeakerphoneOn(false);// 设置此值可在拨打时控制响铃音量am.setMode(AudioManager.MODE_IN_COMMUNICATION);// 设置拨打时响铃音量默认值am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, 8, AudioManager.STREAM_VOICE_CALL);}} catch (IOException e) {e.printStackTrace();}}/*** 判断系统响铃正东相关设置* 1、系统静音 不震动 就两个都不设置* 2、静音震动* 3、只响铃不震动* 4、响铃且震动*/public void initRemoteCallRinging() {int ringerMode = getRingerMode(AndroidApplication.getInstance());if (ringerMode != AudioManager.RINGER_MODE_SILENT) {if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {startVibrator();} else {if (isVibrateWhenRinging()) {startVibrator();}startRing();}}}private int getRingerMode(Context context) {AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);return audio.getRingerMode();}/*** 开始响铃*/private void startRing() {Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);try {mMediaPlayer.setDataSource(AndroidApplication.getInstance(), uri);mMediaPlayer.prepareAsync();} catch (Exception e) {e.printStackTrace();Log.e(TAG, "Ringtone not found : " + uri);try {uri = RingtoneManager.getValidRingtoneUri(AndroidApplication.getInstance());mMediaPlayer.setDataSource(AndroidApplication.getInstance(), uri);mMediaPlayer.prepareAsync();} catch (Exception e1) {e1.printStackTrace();Log.e(TAG, "Ringtone not found: " + uri);}}}/*** 开始震动*/private void startVibrator() {if (mVibrator == null) {mVibrator = (Vibrator) AndroidApplication.getInstance().getSystemService(Context.VIBRATOR_SERVICE);} else {mVibrator.cancel();}mVibrator.vibrate(new long[]{500, 1000}, 0);}/*** 判断系统是否设置了 响铃时振动*/private boolean isVibrateWhenRinging() {ContentResolver resolver = AndroidApplication.getInstance().getApplicationContext().getContentResolver();if (Build.MANUFACTURER.equals("Xiaomi")) {return Settings.System.getInt(resolver, "vibrate_in_normal", 0) == 1;} else if (Build.MANUFACTURER.equals("smartisan")) {return Settings.Global.getInt(resolver, "telephony_vibration_enabled", 0) == 1;} else {return Settings.System.getInt(resolver, "vibrate_when_ringing", 0) == 1;}}/*** 停止震动和响铃*/public void stopRing() {if (mMediaPlayer != null) {mMediaPlayer.reset();}if (mVibrator != null) {mVibrator.cancel();}if (AndroidApplication.getInstance() != null) {//通话时控制音量AudioManager audioManager = (AudioManager) AndroidApplication.getInstance().getApplicationContext().getSystemService(AUDIO_SERVICE);audioManager.setMode(AudioManager.MODE_NORMAL);}}/*** 释放资源*/public void releaseMediaPlayer() {if (mMediaPlayer != null) {mMediaPlayer.release();mMediaPlayer = null;}if (instance != null) {instance = null;}// 退出此页面后应设置成正常模式,否则按下音量键无法更改其他音频类型的音量if (AndroidApplication.getInstance() != null) {AudioManager am = (AudioManager) AndroidApplication.getInstance().getApplicationContext().getSystemService(Context.AUDIO_SERVICE);if (am != null) {am.setMode(AudioManager.MODE_NORMAL);}}}
}

2、陪玩系统源码中悬浮窗的实现

  • 申请权限
  • 将当前通话Activity移动到后台执行
  • 开启悬浮窗服务

1)申请权限

   @TargetApi(19)public static boolean canDrawOverlays(final Context context, boolean needOpenPermissionSetting) {boolean result = true;if (Build.VERSION.SDK_INT >= 23) {try {boolean booleanValue = (Boolean) Settings.class.getDeclaredMethod("canDrawOverlays", Context.class).invoke((Object) null, context);if (!booleanValue && needOpenPermissionSetting) {ArrayList<String> permissionList = new ArrayList();permissionList.add("android.settings.action.MANAGE_OVERLAY_PERMISSION");showPermissionAlert(context, context.getString(R.string.tim_float_window_not_allowed), new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if (-1 == which) {Intent intent = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION", Uri.parse("package:" + context.getPackageName()));context.startActivity(intent);}if (-2 == which) {Toasty.warning(context, "抱歉,您已拒绝DBC获得您的悬浮窗权限,将影响您接听对方发起的语音通话。").show();}}});}Log.i(TAG, "isFloatWindowOpAllowed allowed: " + booleanValue);return booleanValue;} catch (Exception var7) {Log.e(TAG, String.format("getDeclaredMethod:canDrawOverlays! Error:%s, etype:%s", var7.getMessage(), var7.getClass().getCanonicalName()));return true;}} else if (Build.VERSION.SDK_INT < 19) {return true;} else {Object systemService = context.getSystemService(Context.APP_OPS_SERVICE);Method method;try {method = Class.forName("android.app.AppOpsManager").getMethod("checkOp", Integer.TYPE, Integer.TYPE, String.class);} catch (NoSuchMethodException var9) {Log.e(TAG, String.format("NoSuchMethodException method:checkOp! Error:%s", var9.getMessage()));method = null;} catch (ClassNotFoundException var10) {var10.printStackTrace();method = null;}if (method != null) {try {Integer tmp = (Integer) method.invoke(systemService, 24, context.getApplicationInfo().uid, context.getPackageName());result = tmp == 0;} catch (Exception var8) {Log.e(TAG, String.format("call checkOp failed: %s etype:%s", var8.getMessage(), var8.getClass().getCanonicalName()));}}Log.i(TAG, "isFloatWindowOpAllowed allowed: " + result);return result;}}

当然申请悬浮窗全选会有跳转到设置界面这个过程,所以还需要添加判断是否具有悬浮窗权限的判断过程。

2)将当前通话Activity移动到后台执行
这个很简单,就是将Activity的lunchMode改为SingleInstance模式,然后直接调用moveTaskToBack(true);方法,这里传true,表示任何情况下 都会将Acitivty移动到后台。
3)绑定悬浮窗服务,开启陪玩系统源码悬浮窗
创建一个悬浮窗Service,获取WindowManager,在windowManager添加一个自定义的悬浮窗View即可,当然要想悬浮窗可以移动,得重写悬浮窗的,触摸事件。在悬浮窗里面注册一个本地广播,方便改变通话状态,记录通话时间等等。

public class TimFloatWindowService extends Service implements View.OnTouchListener {private WindowManager mWindowManager;private WindowManager.LayoutParams wmParams;private LayoutInflater inflater;/*** 浮动布局view*/private View mFloatingLayout;/*** 容器父布局*/private View mMainView;/*** 开始触控的坐标,移动时的坐标(相对于屏幕左上角的坐标)*/private int mTouchStartX, mTouchStartY, mTouchCurrentX, mTouchCurrentY;/*** 开始时的坐标和结束时的坐标(相对于自身控件的坐标)*/private int mStartX, mStartY, mStopX, mStopY;/*** 判断悬浮窗口是否移动,这里做个标记,防止移动后松手触发了点击事件*/private boolean isMove;/*** 判断是否绑定了服务*/private boolean isServiceBind;/*** 通话状态*/private TextView mAcceptStatus;public class TimBinder extends Binder {public TimFloatWindowService getService() {return TimFloatWindowService.this;}}private BroadcastReceiver mTimBroadCastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (isServiceBind && CommonI.TIM.BROADCAST_FLAG_FLOAT_STATUS.equals(intent.getAction())&& mAcceptStatus != null) {String status = intent.getStringExtra(CommonI.TIM.KEY_ACCEPT_STATUS);mAcceptStatus.setText(status);}}};@Overridepublic IBinder onBind(Intent intent) {isServiceBind = true;initFloating();//悬浮框点击事件的处理return new TimBinder();}@Overridepublic void onCreate() {super.onCreate();//设置悬浮窗基本参数(位置、宽高等)initWindow();//注册 BroadcastReceiver 监听情景模式的切换IntentFilter filter = new IntentFilter();filter.addAction(CommonI.TIM.BROADCAST_FLAG_FLOAT_STATUS);LocalBroadcastManager.getInstance(this).registerReceiver(mTimBroadCastReceiver, filter);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();isServiceBind = false;if (mFloatingLayout != null) {// 移除悬浮窗口mWindowManager.removeView(mFloatingLayout);mFloatingLayout = null;}LocalBroadcastManager.getInstance(this).unregisterReceiver(mTimBroadCastReceiver);}/*** 设置悬浮框基本参数(位置、宽高等)*/private void initWindow() {mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);//设置好悬浮窗的参数wmParams = getParams();// 悬浮窗默认显示以右上角为起始坐标wmParams.gravity = Gravity.RIGHT | Gravity.TOP;// 不设置这个弹出框的透明遮罩显示为黑色wmParams.format = PixelFormat.TRANSLUCENT;//悬浮窗的开始位置,因为设置的是从右上角开始,所以屏幕左上角是x=0;y=0wmParams.x = 40;wmParams.y = 160;//得到容器,通过这个inflater来获得悬浮窗控件inflater = LayoutInflater.from(getApplicationContext());// 获取浮动窗口视图所在布局mFloatingLayout = inflater.inflate(R.layout.layout_tim_float_window, null);// 添加悬浮窗的视图mWindowManager.addView(mFloatingLayout, wmParams);}private WindowManager.LayoutParams getParams() {wmParams = new WindowManager.LayoutParams();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;} else {wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;}//设置可以显示在状态栏上wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;//设置悬浮窗口长宽数据wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;return wmParams;}//加载远端视屏:在这对悬浮窗内内容做操作private void initFloating() {//将子View加载进悬浮窗View//悬浮窗父布局mMainView = mFloatingLayout.findViewById(R.id.layout_dial_float);//加载进悬浮窗的子View,这个VIew来自天转过来的那个Activity里面的那个需要加载的ViewmAcceptStatus = mFloatingLayout.findViewById(R.id.tv_accept_status);
//        View mChildView = renderView.getChildView();
//        mMainView.addView(mChildView);//将需要悬浮显示的Viewadd到mTXCloudVideoView中//悬浮框触摸事件,设置悬浮框可拖动mMainView.setOnTouchListener(this);//悬浮框点击事件mMainView.setOnClickListener(v -> {//绑定了服务才跳转,不绑定服务不跳转if (!isServiceBind) {return;}//在这里实现点击重新回到Activity//从该service跳转至该activity会将该activity从后台唤醒,所以activity会走onReStart()Intent intent = new Intent(TimFloatWindowService.this, TRTCAudioCallActivity.class);//需要Intent.FLAG_ACTIVITY_NEW_TASK,不然会崩溃intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);});}@Overridepublic boolean onTouch(View v, MotionEvent event) {int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:isMove = false;mTouchStartX = (int) event.getRawX();mTouchStartY = (int) event.getRawY();mStartX = (int) event.getX();mStartY = (int) event.getY();break;case MotionEvent.ACTION_MOVE:mTouchCurrentX = (int) event.getRawX();mTouchCurrentY = (int) event.getRawY();wmParams.x -= mTouchCurrentX - mTouchStartX;wmParams.y += mTouchCurrentY - mTouchStartY;Log.i("Tim_FloatingListener", " Cx: " + mTouchCurrentX + " Sx: " + mTouchStartX + " Cy: " + mTouchCurrentY + " Sy: " + mTouchStartY);if (mFloatingLayout != null) {mWindowManager.updateViewLayout(mFloatingLayout, wmParams);}mTouchStartX = mTouchCurrentX;mTouchStartY = mTouchCurrentY;break;case MotionEvent.ACTION_UP:mStopX = (int) event.getX();mStopY = (int) event.getY();if (Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1) {isMove = true;}break;default:break;}//如果是移动事件不触发OnClick事件,防止移动的时候一放手形成点击事件return isMove;}
}

以上就是“用腾讯即时通讯IM和实时音视频实现陪玩系统源码的语音通话功能”的全部内容,希望对大家有帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/26801.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows实时视频通话功能实现流程(实时视频系列四)

实时视频通话系列第四篇。上一篇我们介绍了在Windows环境下如何集成即构音视频SDK&#xff0c;回顾《Windows实时视频通话SDK集成指引》&#xff0c;这一篇将介绍视频直播功能实现流程。 还是以 2 人间的实时视频为例&#xff0c;主要流程如下&#xff1a; 请注意&#xff…

第三篇,私有化部署微信的语音电话,视频聊天IM聊天APP开发源码

前面发布两篇文章&#xff0c;有需要的朋友可以回头看一下&#xff0c;希望可以帮到大家的学习和使用。程序采用了uniapp开发&#xff0c;后端采用PHP&#xff0c;数据库采用MySQL的&#xff0c;程序代码开源&#xff0c;可任意二次开发部署等。 计划实现的功能列表 1、发布消…

Windows语音通话SDK集成及功能实现(实时语音通话四)

实时语音通话系列文章四。本篇讲述Windows环境下集成即构科技语音通话SDK&#xff0c;实现语音通话功能流程。 一、SDK集成指引 1、准备环境 请确保开发环境满足以下技术要求&#xff1a; Visual Studio 2013以上版本 Windows7、Windows8、Windows10或以上版本 麦克风、摄像…

微信原生组件|基于小程序实现音视频通话

1 微信小程序原生推拉流组件功能简介 本文将介绍如何使用微信小程序原生推拉流组件 <live-pusher> 和 <live-player> 进行推拉流&#xff0c;快速实现一个简单的实时音视频通话。 由于微信小程序原生推拉流组件使用起来比较复杂&#xff0c;推荐开发者使用即构封…

Python利用微软Azure免费的语音合成TTS源码分享

我敢保证,用过微软的语音合成后,你就会发现这是世界上最好的语音合成软件。99.99%接近人声自然流程。语调也非常自然,结合其独特的sml标记语言,合成过程中可控制主播声色和音调,以及停顿等各种的内容。 再多的介绍,自己可以百度去了解,本文讲解如何使用免费的方法合成语…

【新知实验室--音视频通话】腾讯云TRTC-实时音视频---多人会议视频通话SDK基础搭建

&#x1f996;我是Sam9029&#xff0c;一个前端 Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 &#x1f431;‍&#x1f409;&#x1f431;‍&#x1f409;恭喜你&#xff0c;若此文你认为写的不错&#xff0c;不要吝啬你的赞扬&#xff0c;求收…

微软MFC下做speech sdk语音识别,消息响应的版本

网上虽然有很多语音识别的教程&#xff0c;但是很多是却少一些部分&#xff0c;笔者在综合了几篇之后&#xff0c;做成功了语音识别&#xff0c;下面是教程。 网上的语音识别分成几种&#xff0c;把语音识别消息放入队列中的是一种&#xff0c;笔者认为这个效率比较高&#xf…

腾讯云TRTC服务实现小程序语音/视屏会议

腾讯云TRTC服务的入门 TRTC 是腾讯云主打全平台互通的多人音视频通话和低延时互动直播解决方案。TRTC服务有多种客户端的支持&#xff0c;对于IOS、Android、React native等都支持的比较好&#xff0c;我们主要在于 IOS、Android、Web三端进行处理&#xff0c;其中 TRTC Web S…

【VS开发】【智能语音处理】Windows下麦克风语音采集

简介 这是我很早以前的大学毕业设计,忽然间找到贴出来以纪念自己的纯真年代...但是因为CSDN不给面子所以导致短短的一篇文章贴了足足7次..他老提时说文章超过了64K,老大,拜托,那是算上了里面的图片大小吧...:-( 本文简单介绍了声卡的工作原理 , 录音的原理以及数字音频的基本知…

【实时语音转文本】PC端实时语音转文本(麦克风外音系统内部音源)

语音转文字这个功能可以应用在视频动态字幕&#xff0c;语音快速输入&#xff0c;实时记录通话内容&#xff0c;高级应用可以在人工智能&#xff0c;语音识别&#xff0c;智能助手方面&#xff0c;还需要一点机器学习可以做出一些好玩的东西&#xff0c;比如PC端AI助理&#xf…

使用微软的语音识别引擎Microsoft Speech API进行语音控制

以下代码来自&#xff1a;http://mmcheng.net/zh/imagespirit/ 本人仅作提取&#xff1a; SREngine语音识别引擎封装类&#xff1a; #pragma once/************************************************************************/ /* Notice: this project is used to support sp…

微软语音合成(tts)服务申请和调用

1、申请账户&#xff1a; https://azure.microsoft.com/zh-cn/free/ 这里有个视频教程&#xff0c;根据此完成申请流程&#xff1a; https://www.bilibili.com/video/BV15a4y1W7re?vd_sourcebf07f28d37849885d215dc3aea189eba 申请完成后&#xff0c;就可以到这里申请资源&am…

英超引入 AI 球探,寻找下一个足球巨星

By 超神经 内容提要&#xff1a;球探对于很多人来说是一个略显神秘的群体&#xff0c;他们对一个球队的建设和发展至关重要。为了提高球探的工作效率&#xff0c;英超伯恩利足球俱乐部最近启用了 AI 球探。 关键词&#xff1a;AI 球探 计算机视觉 姿态识别 最近&#xff0c;中国…

通过whoscored网站对转会球员的评分来比较五大联赛水平高低

我是一个八年级的学生&#xff0c;上学期学习了Python和包括标准差在内的数据统计方法。参考“怕砍不留名”在soccer.hupu.com上的帖子&#xff0c;并且在爸爸的指导下我尝试对欧洲五大足球联赛&#xff08;英超、德甲、西甲、意甲、法甲&#xff09;水平高低做一个比较。 五大…

看卡塔尔世界杯,diff一下足球比赛与软件开发

diff一下足球比赛与软件开发 吐槽世界杯E组&#xff01;类比软件开发与足球比赛教练与架构师的作用 新技术——半自动越位技术世界杯冠军 吐槽世界杯E组&#xff01; 最近博主看了多场世界杯比赛&#xff0c;看的我心力交瘁&#xff0c;欲哭无泪。 从日本与哥斯达黎加那场比赛开…

一个值得关注的技术公众号「腾讯云开发者」

今天向大家推荐的是腾讯云技术社区的公众号&#xff0c;是腾讯官方推出的技术知识分享阵地&#xff0c;每周公开腾讯最新的技术工程方案&#xff08;如微信、健康码、王者荣耀等知名业务的技术架构&#xff09;、ChatGPT 等行业前沿热点解读、研发经验和工作方法等干货&#xf…

踩坑小总结

本来想总结一下自己工作到现在踩过的坑&#xff0c;实在是太多了&#xff0c;自己之前也年轻不懂事&#xff0c;没有记录的习惯&#xff0c;想到多少写多少吧。 1.前、后端分离框架&#xff1a;刚进入工作的时候采用的是easyuissh的框架&#xff0c;前后端一体&#xff0c;后来…

如何调教一个定制化的ChatGPT私人助理,接入自家知识库

大家好&#xff0c;欢迎来到 Crossin的编程教室 &#xff01; 我在之前的文章里介绍过&#xff0c;如何利用 OpenAI 开放的 API&#xff0c;将 ChatGPT 接入自己开发的程序&#xff1a; 把 ChatGPT 加到你自己的程序里 当时开放的模型还是 text-davinci-003。 文章发布后没多久…

ROS (roslaunch turtle_tf turtle_tf_demo.launch)报错-已解决(利用CHAT-GPT修bug)

在使用古月居的ROS入门21讲时&#xff0c;使用turtle_tf包学习tf功能时出现报错&#xff0c;网上的报错都是由于python版本的问题&#xff0c;修改后而无法解决。最后利用CHAT-GPT的修bug提示&#xff0c;最后发现是ros缓存导致报错。在文章的最后还会提供修改python版本的链接…

chatgpt赋能python:Python代码扫描:如何编写高质量的代码

Python 代码扫描&#xff1a;如何编写高质量的代码 如果你是一位有着10年的 Python 编程经验的工程师&#xff0c;你一定知道写出高质量的 Python 代码是多么的重要。但是&#xff0c;即使你是一名经验丰富的 Python 开发者&#xff0c;你的代码仍然可能存在一些隐藏的漏洞和低…