public async Task TestFailedConversionsMissingAsset() { var client = GetClient(); Uri storageUri = new Uri($"https://{TestEnvironment.StorageAccountName}.blob.core.windows.net/{TestEnvironment.BlobContainerName}"); AssetConversionInputOptions input = new AssetConversionInputOptions(storageUri, "boxWhichDoesNotExist.fbx") { // We use SAS for live testing, as there can be a delay before DRAM-based access is available for new accounts. StorageContainerReadListSas = TestEnvironment.SasToken, BlobPrefix = "Input" }; AssetConversionOutputOptions output = new AssetConversionOutputOptions(storageUri) { StorageContainerWriteSas = TestEnvironment.SasToken, BlobPrefix = "Output" }; AssetConversionOptions conversionOptions = new AssetConversionOptions(input, output); string conversionId = Recording.Random.NewGuid().ToString(); AssetConversionOperation conversionOperation = await client.StartConversionAsync(conversionId, conversionOptions); AssetConversion conversion = await conversionOperation.WaitForCompletionAsync(); Assert.AreEqual(AssetConversionStatus.Failed, conversion.Status); Assert.IsNotNull(conversion.Error); // Invalid input provided. Check logs in output container for details. Assert.IsTrue(conversion.Error.Message.ToLower().Contains("invalid input")); Assert.IsTrue(conversion.Error.Message.ToLower().Contains("logs")); }
public void ConvertSimpleAsset() { RemoteRenderingClient client = GetClient(); Uri storageUri = new Uri($"https://{TestEnvironment.StorageAccountName}.blob.core.windows.net/{TestEnvironment.BlobContainerName}"); #region Snippet:StartAnAssetConversion AssetConversionInputOptions inputOptions = new AssetConversionInputOptions(storageUri, "box.fbx"); AssetConversionOutputOptions outputOptions = new AssetConversionOutputOptions(storageUri); AssetConversionOptions conversionOptions = new AssetConversionOptions(inputOptions, outputOptions); // A randomly generated GUID is a good choice for a conversionId. string conversionId = Guid.NewGuid().ToString(); AssetConversionOperation conversionOperation = client.StartConversion(conversionId, conversionOptions); #endregion Snippet:StartAnAssetConversion #region Snippet:QueryAssetConversion AssetConversion conversion = conversionOperation.WaitForCompletionAsync().Result; if (conversion.Status == AssetConversionStatus.Succeeded) { Console.WriteLine($"Conversion succeeded: Output written to {conversion.Output.OutputAssetUri}"); } else if (conversion.Status == AssetConversionStatus.Failed) { Console.WriteLine($"Conversion failed: {conversion.Error.Code} {conversion.Error.Message}"); } #endregion Snippet:QueryAssetConversion }
public async Task ObserveExistingAssetConversion() { ( ObjectAnchorsConversionClient clientWithWorkingInternalMethods, ObjectAnchorsConversionClient client, AssetConversionOptions assetConversionOptions ) = await GetClientsAndConversionOptionsForAsset(assetLocalFilePath); Guid jobId = new Guid((await client.StartAssetConversionAsync(assetConversionOptions)).Id); AssetConversionOperation operation = InstrumentOperation(new AssetConversionOperation(jobId, clientWithWorkingInternalMethods)); await operation.WaitForCompletionAsync(); if (!operation.HasCompletedSuccessfully) { throw new Exception("The asset conversion operation completed with an unsuccessful status"); } string localFileDownloadPath = modelDownloadLocalFilePath; BlobClient downloadBlobClient = InstrumentClient(new BlobClient(operation.Value.OutputModelUri, InstrumentClientOptions(new BlobClientOptions(BlobClientOptions.ServiceVersion.V2019_12_12)))); BlobDownloadInfo downloadInfo = await downloadBlobClient.DownloadAsync(); using (FileStream file = File.OpenWrite(localFileDownloadPath)) { await downloadInfo.Content.CopyToAsync(file); var fileInfo = new FileInfo(localFileDownloadPath); Assert.Greater(fileInfo.Length, 0); } }
public void ConvertMoreComplexAsset() { RemoteRenderingClient client = GetClient(); Uri inputStorageUri = new Uri($"https://{TestEnvironment.StorageAccountName}.blob.core.windows.net/{TestEnvironment.BlobContainerName}"); Uri outputStorageUri = new Uri($"https://{TestEnvironment.StorageAccountName}.blob.core.windows.net/{TestEnvironment.BlobContainerName}"); #region Snippet:StartAComplexAssetConversion AssetConversionInputOptions inputOptions = new AssetConversionInputOptions(inputStorageUri, "bicycle.gltf") { BlobPrefix = "Bicycle" }; AssetConversionOutputOptions outputOptions = new AssetConversionOutputOptions(outputStorageUri) { BlobPrefix = "ConvertedBicycle" }; AssetConversionOptions conversionOptions = new AssetConversionOptions(inputOptions, outputOptions); string conversionId = Guid.NewGuid().ToString(); AssetConversionOperation conversionOperation = client.StartConversion(conversionId, conversionOptions); #endregion Snippet:StartAComplexAssetConversion AssetConversion conversion = conversionOperation.WaitForCompletionAsync().Result; if (conversion.Status == AssetConversionStatus.Succeeded) { Console.WriteLine($"Conversion succeeded: Output written to {conversion.Output.OutputAssetUri}"); } else if (conversion.Status == AssetConversionStatus.Failed) { Console.WriteLine($"Conversion failed: {conversion.Error.Code} {conversion.Error.Message}"); } }
public async Task <Guid> StartAssetConversion() { Guid accountId = new Guid(TestEnvironment.AccountId); string accountDomain = TestEnvironment.AccountDomain; string localFilePath = assetLocalFilePath; Vector3 assetGravity = new Vector3(assetGravityX, assetGravityY, assetGravityZ); float scale = assetScale; AzureKeyCredential credential = new AzureKeyCredential(TestEnvironment.AccountKey); ObjectAnchorsConversionClient client = new ObjectAnchorsConversionClient(accountId, accountDomain, credential); Uri uploadedInputAssetUri = (await client.GetAssetUploadUriAsync()).Value.UploadUri; BlobClient uploadBlobClient = new BlobClient(uploadedInputAssetUri, new BlobClientOptions()); using (FileStream fs = File.OpenRead(localFilePath)) { await uploadBlobClient.UploadAsync(fs); } AssetConversionOptions ingestionJobOptions = new AssetConversionOptions(uploadedInputAssetUri, AssetFileType.FromFilePath(localFilePath), assetGravity, scale); AssetConversionOperation operation = await client.StartAssetConversionAsync(ingestionJobOptions); return(new Guid(operation.Id)); }
public async Task <FileInfo> DownloadConvertedAsset(Guid jobId) { Guid accountId = new Guid(TestEnvironment.AccountId); string accountDomain = TestEnvironment.AccountDomain; AzureKeyCredential credential = new AzureKeyCredential(TestEnvironment.AccountKey); ObjectAnchorsConversionClient client = new ObjectAnchorsConversionClient(accountId, accountDomain, credential); AssetConversionOperation operation = new AssetConversionOperation(jobId, client); await operation.WaitForCompletionAsync(); if (!operation.HasCompletedSuccessfully) { throw new Exception("The asset conversion operation completed with an unsuccessful status"); } string localFileDownloadPath = modelDownloadLocalFilePath; BlobClient downloadBlobClient = new BlobClient(operation.Value.OutputModelUri, new BlobClientOptions()); BlobDownloadInfo downloadInfo = await downloadBlobClient.DownloadAsync(); using (FileStream file = File.OpenWrite(localFileDownloadPath)) { await downloadInfo.Content.CopyToAsync(file); return(new FileInfo(localFileDownloadPath)); } }
public async Task ObserveExistingAssetConversion() { Recording.DisableIdReuse(); string localFilePath = assetLocalFilePath; Vector3 assetGravity = new Vector3(assetGravityX, assetGravityY, assetGravityZ); float scale = assetScale; var clientWithWorkingInternalMethods = CreateClient(); ObjectAnchorsConversionClient client = InstrumentClient(clientWithWorkingInternalMethods); AssetUploadUriResult uploadUriResult = await client.GetAssetUploadUriAsync(); Uri uploadedInputAssetUri = uploadUriResult.UploadUri; BlobClient uploadBlobClient = InstrumentClient(new BlobClient(uploadedInputAssetUri, InstrumentClientOptions(new BlobClientOptions(BlobClientOptions.ServiceVersion.V2019_12_12)))); using (FileStream fs = File.OpenRead(localFilePath)) { await uploadBlobClient.UploadAsync(fs); } AssetConversionOptions assetConversionOptions = new AssetConversionOptions(uploadedInputAssetUri, AssetFileType.FromFilePath(localFilePath), assetGravity, scale); assetConversionOptions.JobId = Recording.Random.NewGuid(); Guid jobId = new Guid((await client.StartAssetConversionAsync(assetConversionOptions)).Id); AssetConversionOperation operation = new AssetConversionOperation(jobId, clientWithWorkingInternalMethods); await operation.WaitForCompletionAsync(); if (!operation.HasCompletedSuccessfully) { throw new Exception("The asset conversion operation completed with an unsuccessful status"); } string localFileDownloadPath = modelDownloadLocalFilePath; BlobClient downloadBlobClient = InstrumentClient(new BlobClient(operation.Value.OutputModelUri, InstrumentClientOptions(new BlobClientOptions(BlobClientOptions.ServiceVersion.V2019_12_12)))); BlobDownloadInfo downloadInfo = await downloadBlobClient.DownloadAsync(); using (FileStream file = File.OpenWrite(localFileDownloadPath)) { await downloadInfo.Content.CopyToAsync(file); var fileInfo = new FileInfo(localFileDownloadPath); Assert.Greater(fileInfo.Length, 0); } }
public async Task TestSimpleConversion() { var client = GetClient(); Uri storageUri = new Uri($"https://{TestEnvironment.StorageAccountName}.blob.core.windows.net/{TestEnvironment.BlobContainerName}"); AssetConversionInputOptions input = new AssetConversionInputOptions(storageUri, "testBox.fbx") { // We use SAS for live testing, as there can be a delay before DRAM-based access is available for new accounts. StorageContainerReadListSas = TestEnvironment.SasToken, BlobPrefix = "Input" }; AssetConversionOutputOptions output = new AssetConversionOutputOptions(storageUri) { StorageContainerWriteSas = TestEnvironment.SasToken, BlobPrefix = "Output" }; AssetConversionOptions conversionOptions = new AssetConversionOptions(input, output); string conversionId = Recording.Random.NewGuid().ToString(); AssetConversionOperation conversionOperation = await client.StartConversionAsync(conversionId, conversionOptions); Assert.AreEqual(conversionId, conversionOperation.Id); Assert.AreEqual(conversionOptions.InputOptions.RelativeInputAssetPath, conversionOperation.Value.Options.InputOptions.RelativeInputAssetPath); Assert.AreNotEqual(AssetConversionStatus.Failed, conversionOperation.Value.Status); AssetConversion conversion = await client.GetConversionAsync(conversionId); Assert.AreEqual(conversion.ConversionId, conversionId); Assert.AreNotEqual(AssetConversionStatus.Failed, conversion.Status); AssetConversion conversion2 = await conversionOperation.WaitForCompletionAsync(); Assert.AreEqual(conversionId, conversion2.ConversionId); Assert.AreEqual(AssetConversionStatus.Succeeded, conversion2.Status); Assert.IsTrue(conversionOperation.Value.Output.OutputAssetUri.EndsWith("Output/testBox.arrAsset")); bool foundConversion = false; await foreach (var s in client.GetConversionsAync()) { if (s.ConversionId == conversionId) { foundConversion = true; } } Assert.IsTrue(foundConversion); }
public async Task WaitForAssetConversionToComplete(Guid jobId) { Guid accountId = new Guid(TestEnvironment.AccountId); string accountDomain = TestEnvironment.AccountDomain; AzureKeyCredential credential = new AzureKeyCredential(TestEnvironment.AccountKey); ObjectAnchorsConversionClient client = new ObjectAnchorsConversionClient(accountId, accountDomain, credential); AssetConversionOperation operation = new AssetConversionOperation(jobId, client); await operation.WaitForCompletionAsync(); if (!operation.HasCompletedSuccessfully) { throw new Exception("The asset conversion operation completed with an unsuccessful status"); } }
public async Task RunFailedAssetConversion() { ( ObjectAnchorsConversionClient clientWithWorkingInternalMethods, ObjectAnchorsConversionClient client, AssetConversionOptions assetConversionOptions ) = await GetClientsAndConversionOptionsForAsset(fakeAssetLocalFilePath); AssetConversionOperation operation = await client.StartAssetConversionAsync(assetConversionOptions); await operation.WaitForCompletionAsync(); if (operation.HasCompletedSuccessfully) { throw new Exception("The asset conversion operation completed with an unexpected successful status"); } // ScaledAssetDimensions should be null when asset conversion fails due to an invalid asset file format // But should not throw an exception trying to access it if (operation.Value.ScaledAssetDimensions != null) { throw new Exception("ScaledAssetDimensions isn't null for a failed job on an invalid asset"); } }
public async Task <int> RunJob(string jobId = "") { int returnValue = 0; try { using AzureEventSourceListener listener = new AzureEventSourceListener( (e, message) => configuration.Logger.LogInformation("[{0:HH:mm:ss:fff}][{1}] {2}", DateTimeOffset.Now, e.Level, message), level: EventLevel.Verbose); // Initialize Object Anchors client ObjectAnchorsConversionClient client = new ObjectAnchorsConversionClient(Guid.Parse(configuration.AccountId), configuration.AccountDomain, new AzureKeyCredential(configuration.AccountKey)); AssetConversionOperation conversionOperation = null; if (string.IsNullOrEmpty(jobId)) { Console.WriteLine($"Asset : {configuration.InputAssetPath}"); Console.WriteLine($"Gravity : {configuration.Gravity}"); Console.WriteLine($"Unit : {Enum.GetName(typeof(AssetLengthUnit), configuration.AssetDimensionUnit)}"); // Upload our asset Console.WriteLine("Attempting to upload asset..."); Uri assetUri = (await client.GetAssetUploadUriAsync()).Value.UploadUri; BlobClient uploadBlobClient = new BlobClient(assetUri); using (FileStream fs = File.OpenRead(configuration.InputAssetPath)) { await uploadBlobClient.UploadAsync(fs); } // Schedule our asset conversion job specifying: // - The uri to our uploaded asset // - Our asset file format // - Gravity direction of 3D asset // - The unit of measurement of the 3D asset Console.WriteLine("Attempting to create asset conversion job..."); var assetOptions = new AssetConversionOptions( assetUri, AssetFileType.FromFilePath(configuration.InputAssetPath), configuration.Gravity, configuration.AssetDimensionUnit); conversionOperation = await client.StartAssetConversionAsync(assetOptions); jobId = conversionOperation.Id; Console.WriteLine($"Successfully created asset conversion job. Job ID: {jobId}"); } else { conversionOperation = new AssetConversionOperation(Guid.Parse(jobId), client); } // Wait for job to complete Console.WriteLine("Waiting for job completion..."); var response = await conversionOperation.WaitForCompletionAsync(new CancellationTokenSource((int)configuration.WaitForJobCompletionTimeout.TotalMilliseconds).Token); returnValue = EvaluateJobResults(response.Value); if (response.Value.ConversionStatus == AssetConversionStatus.Succeeded) { string outputPath = Path.Combine(Path.GetDirectoryName(configuration.InputAssetPath), Path.GetFileNameWithoutExtension(configuration.InputAssetPath) + "_" + jobId + ".ou"); Console.WriteLine($"Attempting to download result as '{outputPath}'..."); BlobClient downloadBlobClient = new BlobClient(response.Value.OutputModelUri); await downloadBlobClient.DownloadToAsync(outputPath); Console.WriteLine("Success!"); } } catch (TaskCanceledException) { returnValue = 1; Console.Error.WriteLine($"Timed out waiting for your job to complete."); } catch (RequestFailedException e) { returnValue = 1; Console.Error.WriteLine($"\nYour request failed:\n\n{e.Message}"); } catch (Exception e) { returnValue = 1; Console.Error.WriteLine($"\n{e.GetType().Name}:\n{e.Message}"); } return(returnValue); }
public async Task <(int result, string jobId)> RunJob(string jobId = "") { int returnValue = 0; try { using AzureEventSourceListener listener = new AzureEventSourceListener( (e, message) => configuration.Logger.LogInformation("[{0:HH:mm:ss:fff}][{1}] {2}", DateTimeOffset.Now, e.Level, message), level: EventLevel.Verbose); // Initialize Object Anchors client ObjectAnchorsConversionClient client = new ObjectAnchorsConversionClient(Guid.Parse(configuration.AccountId), configuration.AccountDomain, new AzureKeyCredential(configuration.AccountKey)); AssetConversionOperation conversionOperation = null; if (string.IsNullOrEmpty(jobId)) { Console.WriteLine($"Asset : {configuration.InputAssetPath}"); Console.WriteLine($"Gravity : {configuration.Gravity}"); Console.WriteLine($"Unit : {Enum.GetName(typeof(AssetLengthUnit), configuration.AssetDimensionUnit)}"); // Upload our asset Console.WriteLine("Attempting to upload asset..."); Uri assetUri = (await client.GetAssetUploadUriAsync()).Value.UploadUri; Console.WriteLine($"\tUpload Uri: {assetUri}"); BlobClient uploadBlobClient = new BlobClient(assetUri, new BlobClientOptions { // The default timeout for HttpClient and RetryOptions.NetworkTimeout is 100 seconds. // Increasing to 5 minutes allows for more flexibility when uploading assets Transport = new HttpClientTransport(new HttpClient { Timeout = TimeSpan.FromMinutes(5) }), Retry = { NetworkTimeout = TimeSpan.FromMinutes(5) } }); await UploadBlobAsync(uploadBlobClient, configuration.InputAssetPath); Console.WriteLine("\nAsset uploaded"); // Schedule our asset conversion job specifying: // - The uri to our uploaded asset // - Our asset file format // - Gravity direction of 3D asset // - The unit of measurement of the 3D asset Console.WriteLine("Attempting to create asset conversion job..."); AssetConversionOptions assetOptions = new AssetConversionOptions( assetUri, AssetFileType.FromFilePath(configuration.InputAssetPath), configuration.Gravity, configuration.AssetDimensionUnit); conversionOperation = await client.StartAssetConversionAsync(assetOptions); jobId = conversionOperation.Id; Console.WriteLine($"Successfully created asset conversion job. Job ID: {jobId}"); } else { conversionOperation = new AssetConversionOperation(Guid.Parse(jobId), client); } // Wait for job to complete Console.WriteLine("Waiting for job completion..."); Response <AssetConversionProperties> response = await conversionOperation.WaitForCompletionAsync(new CancellationTokenSource((int)configuration.WaitForJobCompletionTimeout.TotalMilliseconds).Token); Console.WriteLine( $"\nAsset dimensions calculated during conversion (in meters): " + $"({(response.Value.ScaledAssetDimensions?.X.ToString() ?? "NULL")}," + $" {(response.Value.ScaledAssetDimensions?.Y.ToString() ?? "NULL")}," + $" {(response.Value.ScaledAssetDimensions?.Z.ToString() ?? "NULL")})"); returnValue = EvaluateJobResults(response.Value); if (response.Value.ConversionStatus == AssetConversionStatus.Succeeded) { string tempFolderPath = Path.GetTempPath(); string outputFolderPath = Path.GetDirectoryName(configuration.InputAssetPath); string zipFilePath = Path.Combine(tempFolderPath, Path.GetFileNameWithoutExtension(configuration.InputAssetPath) + "_" + jobId + ".zip"); Console.WriteLine($"Attempting to download zip result here: '{zipFilePath}' ..."); BlobClient downloadBlobClient = new BlobClient(response.Value.OutputModelUri); await downloadBlobClient.DownloadToAsync(zipFilePath); Console.WriteLine($"Unzipping '{zipFilePath}' to '{outputFolderPath}' ..."); ZipFile.ExtractToDirectory(zipFilePath, outputFolderPath, overwriteFiles: true); Console.WriteLine($"Success! Your OU Model is here: '{outputFolderPath}\\{jobId.ToUpperInvariant()}.ou'"); File.Delete(zipFilePath); } else { ConversionErrorCode errorCode = response.Value.ErrorCode; if (errorCode == ConversionErrorCode.AssetCannotBeConverted) { Console.WriteLine("The asset was unable to be converted. Refer to asset conversion guidelines."); } else if (errorCode == ConversionErrorCode.AssetDimensionsOutOfBounds) { Console.WriteLine("Asset dimensions exceeded those allowed for an asset to be converted."); } else if (errorCode == ConversionErrorCode.AssetSizeTooLarge) { Console.WriteLine("The size of the asset file was too large. Refer to asset conversion guidelines for the maximum allowed size."); } else if (errorCode == ConversionErrorCode.InvalidAssetUri) { Console.WriteLine("The URI provided didn't link to an uploaded asset for conversion."); } else if (errorCode == ConversionErrorCode.InvalidFaceVertices) { Console.WriteLine("The uploaded asset included references to vertices that don't exist. Ensure the asset file is correctly formed."); } else if (errorCode == ConversionErrorCode.InvalidGravity) { Console.WriteLine("The provided gravity vector for the asset was incorrect. Ensure it is not the default all-zero vector."); } else if (errorCode == ConversionErrorCode.InvalidJobId) { Console.WriteLine("The provided job ID doesn't exist."); } else if (errorCode == ConversionErrorCode.InvalidScale) { Console.WriteLine("The provided scale for the asset was either zero or negative."); } else if (errorCode == ConversionErrorCode.TooManyRigPoses) { Console.WriteLine("The provided asset had more rig poses than is permitted for an asset to be converted. Refer to asset conversion guidelines for the maximum allowed size."); } else if (errorCode == ConversionErrorCode.ZeroFaces) { Console.WriteLine("The provided asset had no faced. Ensure the asset file is correctly formed."); } else if (errorCode == ConversionErrorCode.ZeroTrajectoriesGenerated) { Console.WriteLine("The provided asset was determined to have no trajectories generated. Ensure the asset file is correctly formed."); } else { Console.WriteLine("An unexpected error was encountered. If the issue persists, reach out to customer support."); } } } catch (AssetFileTypeNotSupportedException ex) { returnValue = 1; string supportedFileTypeList = string.Join(", ", ex.SupportedAssetFileTypes); Console.Error.WriteLine($"The provided asset file of type {ex.AttemptedFileType} is not supported. Supported file types include {supportedFileTypeList}."); } catch (TaskCanceledException) { returnValue = 1; Console.Error.WriteLine($"Timed out waiting for your job to complete."); } catch (RequestFailedException e) { returnValue = 1; Console.Error.WriteLine($"\nYour request failed:\n\n{e.Message}"); } catch (Exception e) { returnValue = 1; PrintException(e); } return(result : returnValue, jobId : jobId); }