/// <summary> /// StartAndAwaitAvatarCalculationAsync implementation /// </summary> private IEnumerator StartAndAwaitAvatarCalculationFunc(string avatarCode, AsyncRequest request) { var avatarRequest = GetAvatarAsync(avatarCode); yield return(avatarRequest.Await()); if (avatarRequest.IsError) { request.SetError(avatarRequest.ErrorMessage); yield break; } var awaitCalculations = connection.AwaitAvatarCalculationsAsync(avatarRequest.Result); yield return(request.AwaitSubrequest(awaitCalculations, finalProgress: 1.0f)); if (request.IsError) { yield break; } if (Strings.BadFinalStates.Contains(awaitCalculations.Result.status)) { request.SetError(string.Format("Avatar {0} calculation finished with status: {1}", awaitCalculations.Result.code, awaitCalculations.Result.status)); yield break; } request.IsDone = true; }
private static void ExecutePoolRequests() { double time = EditorApplication.timeSinceStartup; int count = Resources.instance.requests.Count; for (int i = 0; i < count; i++) { AsyncRequest request = Resources.instance.requests[i]; switch (request.status) { case Status.NeedNewClipStatusRequest: case Status.WaitClipStatusRequest: if (time - request.lastStateTime > waitClipTimout) { request.SetError(Error.Timeout); continue; } else { ExecuteRequest(time, request); break; } case Status.Completed: if (time - request.lastStateTime > 2.0) { Resources.instance.requests.RemoveAt(i); EditorUtility.SetDirty(Resources.instance); i--; count--; } continue; case Status.Error: continue; default: if (time - request.lastStateTime > waitClipTimout) { request.SetError(Error.Timeout); continue; } break; } ExecuteRequest(time, Resources.instance.requests[i]); } if (Resources.instance.requests.Count == 0) { DisposeRefreshEvent(); } }
private static void OnDownloaded(AsyncRequest request, byte[] data, Error error) { //Handle error if (error) { request.SetError(error); return; } //Download completed else { request.status = Status.WritingAsset; } //Write file string savePath = request.saveDirectory + "/" + request.fileName; File.WriteAllBytes(savePath, data); //Import asset savePath = Utils.LocalPath(savePath); AssetDatabase.ImportAsset(savePath, ImportAssetOptions.ForceUpdate); if (request.notificationLink == null) { request.notificationLink = AssetDatabase.LoadAssetAtPath <AudioClip>(savePath); } //Send notification NotificationsPopup.Add("Download completed\n" + request.requestName, MessageType.Info, request.notificationLink); //Delete clip if needed if (!request.deleteClipAtEnd) { request.status = Status.Completed; } else { request.status = Status.SendRequestDeletion; request.currentTask = APIBridge.DeleteClip(request.clipUUID, (string content, Error deleteError) => { if (deleteError) { request.SetError(deleteError); } else { request.status = Status.Completed; } }); } }
private IEnumerator DownloadAvatarFunc(AvatarData avatar, PipelineType pipelineType, AsyncRequest request) { //Update avatar info int retryCount = 3; bool gotAvatar = false; while (!gotAvatar) { if (retryCount == 0) { request.SetError("Unable to download avatar"); yield break; } var updateAvatar = connection.GetAvatarAsync(avatar.code); yield return(Await(updateAvatar, pipelineType)); if (!updateAvatar.IsError) { gotAvatar = true; avatar = updateAvatar.Result; } retryCount--; } // download avatar files retryCount = 3; bool isDownloaded = false; while (!isDownloaded) { if (retryCount == 0) { request.SetError("Unable to download avatar"); yield break; } var downloadAvatar = avatarProvider.DownloadAndSaveAvatarModelAsync(avatar, pipelineType == PipelineType.FACE, true); yield return(Await(downloadAvatar, pipelineType)); isDownloaded = !downloadAvatar.IsError; if (downloadAvatar.IsError) { yield return(new WaitForSeconds(3)); } retryCount--; } request.IsDone = true; }
/// <summary> /// AwaitAvatarCalculationsAsync implementation. /// </summary> private IEnumerator AwaitAvatarCalculationsLoop(AvatarData avatar, AsyncRequest <AvatarData> request) { while (!Strings.FinalStates.Contains(avatar.status)) { yield return(new WaitForSeconds(4)); var avatarStatusRequest = GetAvatarAsync(avatar.code); yield return(avatarStatusRequest); if (avatarStatusRequest.Status.Value == (long)StatusCode.Code.NOT_FOUND) { Debug.LogWarning("404 error most likely means that avatar was deleted from the server"); request.SetError(string.Format("Avatar status response: {0}", avatarStatusRequest.ErrorMessage)); yield break; } if (avatarStatusRequest.Status.Value == (long)StatusCode.Code.TOO_MANY_REQUESTS_THROTTLING) { Debug.LogWarning("Too many requests!"); yield return(new WaitForSeconds(10)); } if (avatarStatusRequest.IsError) { Debug.LogWarningFormat("Status polling error: {0}", avatarStatusRequest.ErrorMessage); // Most likely this is a temporary issue. Keep polling. continue; } avatar = avatarStatusRequest.Result; Debug.LogFormat("Status: {0}, progress: {1}%", avatar.status, avatar.progress); request.State = AvatarSdkMgr.Str(avatar.status); if (avatar.status == Strings.Computing) { request.Progress = (float)avatar.progress / 100; } } if (Strings.GoodFinalStates.Contains(avatar.status)) { request.Result = avatar; request.IsDone = true; } else { request.SetError(string.Format("Avatar calculations failed, status: {0}", avatar.status)); } }
/// <summary> /// DeleteAvatarAsync implementation /// </summary> private IEnumerator DeleteAvatarFunc(string avatarCode, AsyncRequest request) { var avatarRequest = GetAvatarAsync(avatarCode); yield return(avatarRequest); if (avatarRequest.IsError) { request.SetError(avatarRequest.ErrorMessage); yield break; } var deleteRequest = connection.DeleteAvatarAsync(avatarRequest.Result); yield return(request.AwaitSubrequest(deleteRequest, 0.5f)); if (request.IsError) { yield break; } CoreTools.DeleteAvatarFiles(avatarCode); request.IsDone = true; }
/// <summary> /// Loop until the desired number of pages is downloaded. /// </summary> public virtual IEnumerator AwaitMultiplePages <T> (string url, AsyncRequest <T[]> request, int maxItems = int.MaxValue) { List <T> items = new List <T> (); do { var pageRequest = AvatarJsonPageRequest <T> (url); yield return(pageRequest); if (pageRequest.IsError) { request.SetError(string.Format("Page request failed. Error: {0}", pageRequest.ErrorMessage)); yield break; } // Debug.LogFormat ("Successfully loaded page {0}", url); var page = pageRequest.Result; for (int i = 0; i < page.content.Length && items.Count < maxItems; ++i) { items.Add(page.content[i]); } url = page.nextPageUrl; } while (items.Count < maxItems && !string.IsNullOrEmpty(url)); request.Result = items.ToArray(); request.IsDone = true; }
/// <summary> /// GetAvatarAsync implementation /// </summary> private IEnumerator GetAvatarFunc(string avatarCode, AsyncRequest <AvatarData> request) { if (UseCache && avatarsDataCache.ContainsKey(avatarCode)) { request.Result = avatarsDataCache[avatarCode]; request.IsDone = true; yield break; } var avatarRequest = connection.GetAvatarAsync(avatarCode); yield return(avatarRequest); if (avatarRequest.IsError) { request.SetError(avatarRequest.ErrorMessage); yield break; } if (UseCache && string.Compare(avatarRequest.Result.status.ToLower(), "Completed") == 0) { avatarsDataCache[avatarCode] = avatarRequest.Result; } request.Result = avatarRequest.Result; request.IsDone = true; }
private static void ExecuteRequest(double time, AsyncRequest request) { //Do nothing if request is waiting for API response if (request.status == Status.WaitClipStatusRequest) { return; } //The next steps are only used to send status request if (request.status != Status.NeedNewClipStatusRequest) { return; } //Force a delay in requests to avoid flooding the api double delta = time - request.lastCheckTime; if (delta < 0.0f || delta > checkCooldown) { request.lastCheckTime = time; } else { return; } //Send GetClip request request.currentTask = APIBridge.GetClip(request.clipUUID, (ResembleClip clip, Error error) => { //Error if (error) { request.SetError(error); } //Receive an response else { //Clip is ready - Start downloading if (clip.finished) { DownloadClip(request, clip.link); //Get phonemes if (request.phonemeCallback != null) { request.phonemeCallback.Invoke(clip.phonemesRaw); } } //Clip is not ready - Mark to create a request next time else { request.status = Status.NeedNewClipStatusRequest; } } }); request.status = Status.WaitClipStatusRequest; }
/// <summary> /// MoveToLocalStorageAvatarModelAsync implementation /// </summary> private IEnumerator MoveAvatarModelToLocalStorage(string avatarCode, bool withHaircutPointClouds, bool withBlendshapes, AsyncRequest request) { var avatarRequest = GetAvatarAsync(avatarCode); yield return(avatarRequest.Await()); if (avatarRequest.IsError) { request.SetError(avatarRequest.ErrorMessage); yield break; } yield return(DownloadAndSaveAvatarModel(avatarRequest.Result, withHaircutPointClouds, withBlendshapes, request)); }
/// <summary> /// AuthorizeAsync implementation. /// </summary> private IEnumerator Authorize(AsyncRequest request) { var accessCredentials = AuthUtils.LoadCredentials(); if (accessCredentials == null || string.IsNullOrEmpty(accessCredentials.clientSecret)) { request.SetError("Could not find API keys! Please provide valid credentials via Window->ItSeez3D Avatar SDK"); yield break; } var authRequest = AuthorizeClientCredentialsGrantTypeAsync(accessCredentials); yield return(request.AwaitSubrequest(authRequest, 0.5f)); if (request.IsError) { yield break; } tokenType = authRequest.Result.token_type; accessToken = authRequest.Result.access_token; Debug.LogFormat("Successful authentication!"); // guarantees we re-register a Player if clientId changes var playerIdentifier = string.Format("player_uid_{0}", accessCredentials.clientId.Substring(0, accessCredentials.clientId.Length / 3)); if (string.IsNullOrEmpty(playerUID)) { playerUID = AvatarSdkMgr.Storage().LoadPlayerUID(playerIdentifier); } if (string.IsNullOrEmpty(playerUID)) { Debug.Log("Registering new player UID"); var playerRequest = RegisterPlayerAsync(); yield return(request.AwaitSubrequest(playerRequest, 1)); if (request.IsError) { yield break; } playerUID = playerRequest.Result.code; AvatarSdkMgr.Storage().StorePlayerUID(playerIdentifier, playerUID); } request.IsDone = true; }
/// <summary> /// GetAllAvatarsAsync implementation /// </summary> private IEnumerator GetAllAvatarsFunc(int maxItems, AsyncRequest <string[]> request) { var avatarsRequest = connection.GetAvatarsAsync(maxItems); yield return(avatarsRequest); if (avatarsRequest.IsError) { request.SetError(avatarsRequest.ErrorMessage); yield break; } var avatarsData = avatarsRequest.Result.OrderBy(av => DateTime.Parse(av.created_on)).Reverse().ToArray(); request.Result = avatarsData.Select(a => a.code).ToArray(); request.IsDone = true; }
/// <summary> /// GetHaircutDataAsync implementation /// </summary> private IEnumerator GetHaircutDataFunc(string avatarCode, string haircutId, AsyncRequest <AvatarHaircutData> request) { bool takeFromCache = UseCache && haircutsDataCache.ContainsKey(avatarCode); if (takeFromCache) { request.Result = haircutsDataCache[avatarCode].FirstOrDefault(h => string.Compare(h.identity, haircutId) == 0); } else { // get AvatarData firstly. // If you would like to make multiple requests for getting haircut data, it is better to get AvatarData only once and store it somewhere var avatarRequest = GetAvatarAsync(avatarCode); yield return(avatarRequest.Await()); if (avatarRequest.IsError) { request.SetError(avatarRequest.ErrorMessage); yield break; } var haircutInfoRequest = connection.GetHaircutsAsync(avatarRequest.Result); yield return(request.AwaitSubrequest(haircutInfoRequest, 0.9f)); if (request.IsError) { yield break; } if (UseCache) { haircutsDataCache.Add(avatarCode, haircutInfoRequest.Result); } AvatarHaircutData haircutData = haircutInfoRequest.Result.FirstOrDefault(h => string.Compare(h.identity, haircutId) == 0); if (haircutData == null) { Debug.LogErrorFormat("There is no {0} haircut for avatar with code: {1}", haircutId, avatarCode); yield break; } request.Result = haircutData; } request.IsDone = true; }
/// <summary> /// GetHaircutsIdAsync implementation /// </summary> private IEnumerator GetHaircutsIdFunc(string avatarCode, AsyncRequest <string[]> request) { bool takeFromCache = UseCache && haircutsDataCache.ContainsKey(avatarCode); if (takeFromCache) { request.Result = haircutsDataCache[avatarCode].Select(h => h.identity).ToArray(); } else { var avatarRequest = GetAvatarAsync(avatarCode); yield return(avatarRequest.Await()); if (avatarRequest.IsError) { request.SetError(avatarRequest.ErrorMessage); yield break; } if (supportedHaircutsPipelines.Contains(avatarRequest.Result.pipeline)) { var haircutInfoRequest = connection.GetHaircutsAsync(avatarRequest.Result); yield return(request.AwaitSubrequest(haircutInfoRequest, 0.9f)); if (request.IsError) { yield break; } request.Result = haircutInfoRequest.Result.Select(h => h.identity).ToArray(); if (UseCache) { haircutsDataCache.Add(avatarCode, haircutInfoRequest.Result); } } else { Debug.LogFormat("{0} doesn't support haircuts", avatarRequest.Result.pipeline); } } request.IsDone = true; }
private IEnumerator GetResourcesFunc(AvatarResourcesSubset resourcesSubset, PipelineType pipelineType, AsyncRequest <AvatarResources> request) { if (avatarResourcesCache[pipelineType].ContainsKey(resourcesSubset)) { request.Result = avatarResourcesCache[pipelineType][resourcesSubset]; request.IsDone = true; } else { var resourcesWebRequest = connection.GetResourcesAsync(pipelineType, resourcesSubset); yield return(resourcesWebRequest); if (resourcesWebRequest.IsError) { Debug.LogError(resourcesWebRequest.ErrorMessage); request.SetError(resourcesWebRequest.ErrorMessage); yield break; } AvatarResources avatarResources = GetResourcesFromJson(resourcesWebRequest.Result); avatarResourcesCache[pipelineType].Add(resourcesSubset, avatarResources); request.IsDone = true; request.Result = avatarResources; } }
/// <summary> Build a async request for a clip. This request handles patching, downloading and notifications. </summary> public static AsyncRequest Make(Clip clip) { //Build request AsyncRequest request = new AsyncRequest(); request.status = Status.BuildRequest; string savePath = clip.GetSavePath(); request.saveDirectory = Path.GetDirectoryName(savePath); request.fileName = Path.GetFileName(savePath); request.requestName = clip.speech.name + " > " + clip.clipName; request.clipUUID = clip.uuid; request.notificationLink = clip; //Generate place holder request.status = Status.GeneratePlaceHolder; clip.clip = request.GeneratePlaceHolder(); //Phonemes stuff bool includePhonemes = clip.speech.includePhonemes; string voiceUUID = clip.speech.voiceUUID; if (includePhonemes) { request.phonemeCallback = clip.SetPhonemesRaw; } //No UUID - Create new clip request.status = Status.SendDataToAPI; if (string.IsNullOrEmpty(request.clipUUID)) { //Create new clip ClipPatch.Data data = new ClipPatch.Data(clip.clipName, clip.text.BuildResembleString(), voiceUUID); request.currentTask = APIBridge.CreateClip(data, includePhonemes, (ClipStatus status, Error error) => { request.clipUUID = clip.uuid = status.id; RegisterRequestToPool(request); }); } else { ClipPatch patch = new ClipPatch(clip.clipName, clip.text.BuildResembleString(), voiceUUID, clip.speech.includePhonemes); //Bypass the api check for similarities. if (Settings.forceGeneration) { //Patch clip request.currentTask = APIBridge.UpdateClip(request.clipUUID, patch, (string content, Error patchError) => { RegisterRequestToPool(request); }); } //Check the api for similarities else { //Get existing clip APIBridge.GetClip(clip.uuid, (ResembleClip apiClip, Error error) => { //Handle error if (error) { request.SetError(error); } else { //No changes - Download existing clip if (apiClip.finished && patch.CompareContent(apiClip)) { APIBridge.DownloadClip(apiClip.link, (byte[] data, Error downloadError) => { OnDownloaded(request, data, downloadError); RegisterRequestToPool(request); }); } //Changes - Patch existing clip else { request.currentTask = APIBridge.UpdateClip(request.clipUUID, patch, (string content, Error patchError) => { RegisterRequestToPool(request); }); } } }); } } //Return the request return(request); }
private IEnumerator GenerateAvatarFunc(byte[] selectedImageBytes, PipelineType pipelineType, AsyncRequest <AvatarData> request) { UpdateAvatarState(WebglAvatarState.UPLOADING, pipelineType); var defaultResourcesRequest = avatarProvider.ResourceManager.GetResourcesAsync(AvatarResourcesSubset.DEFAULT, pipelineType); yield return(Await(defaultResourcesRequest, pipelineType)); // Generate all haircuts and default blendshapes to play animations var allResourcesRequest = avatarProvider.ResourceManager.GetResourcesAsync(AvatarResourcesSubset.ALL, pipelineType); yield return(Await(allResourcesRequest, pipelineType)); if (defaultResourcesRequest.IsError || allResourcesRequest.IsError) { string msg = "Unable to get resources list"; Debug.LogError(msg); UpdateAvatarState(WebglAvatarState.FAILED, pipelineType); request.SetError(msg); yield break; } AvatarResources resources = allResourcesRequest.Result; resources.blendshapes = defaultResourcesRequest.Result.blendshapes; var createAvatar = connection.CreateAvatarWithPhotoAsync("test_avatar", "test_description", selectedImageBytes, false, pipelineType, resources); yield return(Await(createAvatar, pipelineType)); if (createAvatar.IsError) { Debug.LogError(createAvatar.ErrorMessage); UpdateAvatarState(WebglAvatarState.FAILED, pipelineType); request.SetError(createAvatar.ErrorMessage); yield break; } var avatar = createAvatar.Result; var savePhoto = CoreTools.SaveAvatarFileAsync(selectedImageBytes, avatar.code, AvatarFile.PHOTO); yield return(savePhoto); var savePipeline = CoreTools.SaveAvatarFileAsync(Encoding.ASCII.GetBytes(pipelineType.GetPipelineTypeName()), avatar.code, AvatarFile.PIPELINE_INFO); yield return(savePipeline); if (savePhoto.IsError) { Debug.LogError(savePhoto.ErrorMessage); UpdateAvatarState(WebglAvatarState.FAILED, pipelineType); request.SetError(savePhoto.ErrorMessage); yield break; } UpdateAvatarState(WebglAvatarState.CALCULATING_IN_CLOUD, pipelineType); var awaitCalculations = connection.AwaitAvatarCalculationsAsync(avatar); yield return(Await(awaitCalculations, pipelineType)); if (awaitCalculations.IsError) { Debug.LogError(awaitCalculations.ErrorMessage); UpdateAvatarState(WebglAvatarState.FAILED, pipelineType); request.SetError(awaitCalculations.ErrorMessage); yield break; } AvatarData avatarData = awaitCalculations.Result; UpdateAvatarState(WebglAvatarState.DOWNLOADING, pipelineType); var downloadRequest = DownloadAvatarAsync(avatarData, pipelineType); yield return(downloadRequest); if (downloadRequest.IsError) { Debug.LogError(downloadRequest.ErrorMessage); UpdateAvatarState(WebglAvatarState.FAILED, pipelineType); request.SetError(downloadRequest.ErrorMessage); yield break; } UpdateAvatarState(WebglAvatarState.FINISHED, pipelineType); request.Result = avatarData; request.IsDone = true; }