# 一、接入流程

# 1.直播入口检测 (在登录后执行)

FString UserInfo = FString::Printf(TEXT("{\"openid\":\"%s\",\"appid\":\"%s\",\"renderer\":\"%s\"}"),*UserId, *WxAppId,*FPlatformMisc::GetPrimaryGPUBrand());
UWXGameLiveEngine::CheckSupport(UserInfo, TestEnv, [=](int result, const FString& message)
{
        //处理回调结果
    if (result == 0) {
      // 显示直播入口
      LiveButton->SetVisibility(ESlateVisibility::Visible);
      // 初始化SDK
      UWXGameLiveEngine::Init(mGameName,mGameAppId,mIlinkAppId);
      // 启用跳转视频号能力
      UWXGameLiveEngine::EnableStartChannelLive(true);
      // 启用内部麦克风权限申请逻辑
      UWXGameLiveEngine::AuthorizeInnerAudio(true); 
      // 启用SDK内部麦克风采集
      UWXGameLiveEngine::EnableInnerAudioCapture(true);
      // 设置直播事件监听
      UWXGameLiveEngine::SetLiveEventObserver(this);
    }
    else
    {
      GEngine->AddOnScreenDebugMessage(-1,200.f,FColor::Blue, FString::Printf(TEXT("CheckSupport result: %d  , message: %s"), result, *message));
    }
});

# 2.拉起挂件直播

void LaunchLiveWidget()
{
    // LoadLiveWebView必须在Init之后调用
    UWXGameLiveEngine::LoadLiveWidget();
}

# 3.处理视频号授权事件

 void OnRequireAuthorize()
{
// 使用MSDK进行视频号授权
#if PLATFORM_IOS || PLATFORM_ANDROID
	MSDKLogin::ChannelPermissionAuth("WeChat", "snsapi_channels_livestream");
#endif
}

# 4.处理打开链接事件

void OnOpenUrl(const FString& url, int screenType, bool isFullScreen, bool isBrowser)
{
   // eg:使用MSDKWebView打开链接
	MSDKWebView::OpenUrl(TCHAR_TO_UTF8(*url),screenType, isFullScreen, true, "", isBrowser);
}

# 5.处理跳转微信事件

 void OnStartChannelLive(const FString& liveJsonInfo)
{
	MSDKFriendReqInfo ReqInfo;
 
	ReqInfo.type = kMSDKFriendReqTypeWXChannelStartLive;
	ReqInfo.extraJson = TCHAR_TO_UTF8(*liveJsonInfo);
 
	MSDKFriend::SendMessage(ReqInfo,"WeChat");
}

# 6.处理开播事件

void OnStartLive(bool isAudioPermissionGranted)
{
   // 启动视频采集
    m_WXVideoCapture.Reset(new WXVideoCapture());
    m_WXVideoCapture->StartCapturingFrames();
    
    if (isAudioPermissionGranted) {
        // 如果没有使用SDK内部麦克风采集,需要在这里启动第三方语音引擎(如GVoice)的PCM数据回调
    } else {
        // 用户拒绝了麦克风权限,可以给下提示:没有麦克风权限,无法采集主播语音
    }
    
}

# 7.处理关播事件

void OnStopLive()
{
   // 停止视频采集
	if (m_WXVideoCapture.IsValid()) 
	{
	    m_WXVideoCapture->StopCapturingFrames();
	    m_WXVideoCapture.Release();
	}  
   
    // 如果使用了第三方语音引擎的PCM采集,这里需要停止采集
}

# 8.GVoice 语音采集


# 9.微信拉起游戏开播

  1. 监听游戏被第三方应用拉起时,传递过来的参数,确认是被微信视频号拉起时,调用OnMessageFromWeChat接口将相关参数传给直播SDK。 以MSDK为例,示例如下:
void UWXLiveUserWidget::OnBaseRetNotify(const MSDKBaseRet& baseRet)
{
	GEngine->AddOnScreenDebugMessage(-1,200.f,FColor::Blue, FString::Printf(TEXT("OnBaseRetNotify methodNameID: %d"), baseRet.methodNameID));
	UE_LOG(WXLiveLog, Log, TEXT("OnBaseRetNotify methodNameID: %d"), baseRet.methodNameID);
	if (baseRet.methodNameID == kMethodNameChannelPermissionAuth)
	{
		// 视频号授权票据返回
		std::string ExtraInfo = baseRet.extraJson;
		#if PLATFORM_ANDROID
		// android平台上,msdk返回的tdiAuthBuffer字段中多出了3个换行符,需要msdk修复,这里先临时处理下
		std::string::size_type pos = 0;
		std::string target = "\\n";
		while ((pos = ExtraInfo.find(target,pos)) != std::string::npos)  
		{
			ExtraInfo.erase(pos, target.length());
		}
		//ExtraInfo.erase(std::remove(ExtraInfo.begin(),ExtraInfo.end(),'\n'),ExtraInfo.end());
		#endif
		TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(FString(ExtraInfo.c_str()));
		TSharedPtr<FJsonObject> rRoot;
		if (FJsonSerializer::Deserialize(Reader, rRoot) && rRoot.IsValid())
		{
			if (rRoot->HasField(TEXT("tdiAuthBuffer")))
			{
				TArray<uint8> TdiAuthBuffer;
				const FString STdiAuthBuffer = rRoot->GetStringField(TEXT("tdiAuthBuffer"));
				FBase64::Decode(STdiAuthBuffer,TdiAuthBuffer);
				GEngine->AddOnScreenDebugMessage(-1,200.f,FColor::Blue, FString::Printf(TEXT("OnBaseRetNotify STdiAuthBuffer: %s"), *STdiAuthBuffer));
				UWXGameLiveEngine::AuthorizeFinish(baseRet.retCode, TdiAuthBuffer);
			}
		}
	}
	else if (baseRet.methodNameID == kMethodNameWakeUp) 
	{
		// 视频号拉起游戏开播
		const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(FString(baseRet.extraJson.c_str()));
		TSharedPtr<FJsonObject> rRoot;
		// bool bSuccessful = FJsonSerializer::Deserialize(Reader, rRoot);
		if (FJsonSerializer::Deserialize(Reader, rRoot) && rRoot.IsValid())
		{
			const TSharedPtr<FJsonObject>* ParamsObj = nullptr;
			GEngine->AddOnScreenDebugMessage(-1,200.f,FColor::Blue, FString::Printf(TEXT("OnBaseRetNotify retCode: %d extraJson: %s"), baseRet.retCode,*FString(baseRet.extraJson.c_str())));

			const FString Params = rRoot->GetStringField(TEXT("params"));

			const TSharedRef<TJsonReader<>> ParamsReader = TJsonReaderFactory<>::Create(Params);
			TSharedPtr<FJsonObject> ParamsObject;

			if (FJsonSerializer::Deserialize(ParamsReader, ParamsObject) && ParamsObject.IsValid())
			{
				// 接受来自视频号的参数
				FString msgFromChannel;
#if PLATFORM_ANDROID
				ParamsObject->TryGetStringField(TEXT("_wxappextendobject_extInfo"),msgFromChannel);
#elif PLATFORM_IOS
				ParamsObject->TryGetStringField(TEXT("messageExt"),msgFromChannel);
#endif
				UE_LOG(WXLiveLog, Log, TEXT("OnBaseRetNotify msgFromChannel: %s"), *msgFromChannel);
				GEngine->AddOnScreenDebugMessage(-1,200.f,FColor::Blue, FString::Printf(TEXT("OnBaseRetNotify msgFromChannel: %s"), *msgFromChannel));
				if (msgFromChannel.Contains(TEXT("WeChatLive_ShiPinHao")))
				{
					UWXGameLiveEngine::OnMessageFromWeChat(msgFromChannel);
				}
			}
		}
	}

# 注意事项

  1. 使用Fmod for Unreal音频引擎时,启用WXGameLive.Build.cs文件中以下几行注释:
		/*********************FMOD Setting Begin******************/
		#if UE_4_19_OR_LATER
			PublicDefinitions.Add("USE_FMOD");
		#else
			Definitions.Add("USE_FMOD");
		#endif


		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"FMODStudio",
			}
		);
		/*********************FMOD Setting End******************/
  1. 使用Wwise情况下,sdk提供了wwise的录音插件:WGLive,游戏侧需将该插件挂在到wwise的工程的master总线上后,重新build sound bank资源。并且启用WXGameLive.Build.cs文件中以下一行注释
PublicAdditionalLibraries.Add(Path.Combine(LibDir, "wwise/libWGLiveFX.a"));
  1. GVoice的时序需要特别注意:
    a. mVoiceEngine.invoke(4, 1, 0, null) 必须在麦克风权限同意后再调用
    b. mVoiceEngine.invoke(5, 1, 1, null) 必须在mVoiceEngine.Init()之前调用

  2. 游戏注销当前登录的帐号时需要关闭当前的直播,调用如下接口:

UWXGameLiveEngine::PostGameMessage(TEXT("{\"type\":\"finishLive\"}"),0);

# 一键开播完整流程图

flow_chart