diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 43ed123b3ce6..95eed4f894d7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -34,6 +34,7 @@ /sdk/batch/ @dpwatrous @paterasMSFT @zfengms @deyaaeldeen # PRLabel: %Communication +/sdk/communication/communication-calling-server/ @zihzhan-msft @cochi2 /sdk/communication/communication-identity/ @Azure/acs-identity-sdk /sdk/communication/communication-chat/ @LuChen-Microsoft /sdk/communication/communication-phone-numbers/ @miguhern @danielav7 @whisper6284 @AlonsoMondal diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 9d7c61dda365..9bdff46fb36c 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -48,6 +48,7 @@ specifiers: '@rush-temp/arm-videoanalyzer': file:./projects/arm-videoanalyzer.tgz '@rush-temp/arm-webpubsub': file:./projects/arm-webpubsub.tgz '@rush-temp/attestation': file:./projects/attestation.tgz + '@rush-temp/communication-calling-server': file:./projects/communication-calling-server.tgz '@rush-temp/communication-chat': file:./projects/communication-chat.tgz '@rush-temp/communication-common': file:./projects/communication-common.tgz '@rush-temp/communication-identity': file:./projects/communication-identity.tgz @@ -194,6 +195,7 @@ dependencies: '@rush-temp/arm-videoanalyzer': file:projects/arm-videoanalyzer.tgz '@rush-temp/arm-webpubsub': file:projects/arm-webpubsub.tgz '@rush-temp/attestation': file:projects/attestation.tgz + '@rush-temp/communication-calling-server': file:projects/communication-calling-server.tgz '@rush-temp/communication-chat': file:projects/communication-chat.tgz '@rush-temp/communication-common': file:projects/communication-common.tgz '@rush-temp/communication-identity': file:projects/communication-identity.tgz @@ -1603,7 +1605,6 @@ packages: /@opentelemetry/node/0.22.0_@opentelemetry+api@1.0.3: resolution: {integrity: sha512-+HhGbDruQ7cwejVOIYyxRa28uosnG8W95NiQZ6qE8PXXPsDSyGeftAPbtYpGit0H2f5hrVcMlwmWHeAo9xkSLA==} engines: {node: '>=8.0.0'} - deprecated: Package renamed to @opentelemetry/sdk-trace-node peerDependencies: '@opentelemetry/api': ^1.0.0 dependencies: @@ -8632,7 +8633,7 @@ packages: dev: false file:projects/arm-apimanagement.tgz: - resolution: {integrity: sha512-Fhy/ZVzzeHAI6KpTIXUXFfm/Snv32HwUcw9otxvEujalkzeZr8Zqj2A5sL+Z4JCsXIiEdRu0ERDezW/zC9zBQw==, tarball: file:projects/arm-apimanagement.tgz} + resolution: {integrity: sha512-omQocPXL4sX90Auam4HZhWZxdMAXN2lLUqmkfqrJTBR45GiDSX3ozqPioi9OOCKPVyeIRI5UCImM6MVYdWqR6A==, tarball: file:projects/arm-apimanagement.tgz} name: '@rush-temp/arm-apimanagement' version: 0.0.0 dependencies: @@ -8650,13 +8651,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-appplatform.tgz: - resolution: {integrity: sha512-15DNfLDgoFCvpMnOXeTUvM6JaMX4itfDHbbssMmedCSBRsuoIYI7v+Aqoe6PlM0X5j3ihRh28DE3TuaGK3zz3g==, tarball: file:projects/arm-appplatform.tgz} + resolution: {integrity: sha512-T0o1M9Quyi1fBqxV5Ud3sGP3k0IvZiY7FhR+/INeIJTxjuoLm9A4WC0w0O8nfdOFaMpBCHFzs9LAPAqgLPe8zg==, tarball: file:projects/arm-appplatform.tgz} name: '@rush-temp/arm-appplatform' version: 0.0.0 dependencies: @@ -8674,9 +8672,6 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-appservice.tgz: @@ -8717,7 +8712,7 @@ packages: dev: false file:projects/arm-compute.tgz: - resolution: {integrity: sha512-FaD4eIsZKSPaCdi+sZG/rLdxIK53N2kLSPC9WpA9R16MNspd5oGDdIrNBaqMm0wIiGVgmaF0I/Bz0xhjwpJRlg==, tarball: file:projects/arm-compute.tgz} + resolution: {integrity: sha512-S1XrLCLkKlv9rF9JwaiXFfaYHJfui5KxYt14LkOGUZlG4Cpy51S6Cq6FLiycSXbEhuupEfA/zNH6gQ+QdRKwvQ==, tarball: file:projects/arm-compute.tgz} name: '@rush-temp/arm-compute' version: 0.0.0 dependencies: @@ -8737,12 +8732,11 @@ packages: typescript: 4.2.4 uglify-js: 3.14.2 transitivePeerDependencies: - - debug - supports-color dev: false file:projects/arm-containerregistry.tgz: - resolution: {integrity: sha512-Rid9aO/03T0CWDM7YAIbD+EOH9XPisQuabEDScieEtcQBVApQEoGa26or+BEiuGyZckW4qINlAHRAllqrre4eQ==, tarball: file:projects/arm-containerregistry.tgz} + resolution: {integrity: sha512-eML9RRuPgSJ8JV8BsD2v6xKWP67uDGwYDZzTTsJVaUpN4W+1a2TSxzqmHiw0H5AHCpUW9U5v9cvImbxZSFVUIA==, tarball: file:projects/arm-containerregistry.tgz} name: '@rush-temp/arm-containerregistry' version: 0.0.0 dependencies: @@ -8760,13 +8754,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-containerservice.tgz: - resolution: {integrity: sha512-8dMhPZWfeynHxwOOjEWch3Im4U/Xspmhtka9ydrQ9OSlqyvKBX+NUYXlNOGBDh+REpaU/Aw91HHs1djC4T9fCA==, tarball: file:projects/arm-containerservice.tgz} + resolution: {integrity: sha512-dnDtHoSH9nRPyYETislryt3GQWsWDr/WpOaWSVgvDT/KF4XjHU+SA/wEdGAISugXWouXQVry36DqeZtU1Mxt4A==, tarball: file:projects/arm-containerservice.tgz} name: '@rush-temp/arm-containerservice' version: 0.0.0 dependencies: @@ -8784,13 +8775,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-databricks.tgz: - resolution: {integrity: sha512-XaemWrbL7egMo3Z96O0TViAxYXm8zBldQJ/LqzH3opwYmClVCzQ7NJawaNEV7XBplB4c/27YOhxDbTt15krrLA==, tarball: file:projects/arm-databricks.tgz} + resolution: {integrity: sha512-t6otub9/jRDg0NTKRSRC8ADoctIa5M6ME8RnJtFj6A5PU2xjg1kwEVAnEPb+OKhxcR+t1cvQLs9L2gfNKQLeXg==, tarball: file:projects/arm-databricks.tgz} name: '@rush-temp/arm-databricks' version: 0.0.0 dependencies: @@ -8808,13 +8796,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-eventgrid.tgz: - resolution: {integrity: sha512-+XOrFix8ZFVM4KwSCHmgXW5R2T/NPMLuaz69Ml0hPJBGDg8Fgjgj5jErmZ8ZEXpZFkI3i3ax0d8fBB1mNY9+SQ==, tarball: file:projects/arm-eventgrid.tgz} + resolution: {integrity: sha512-wRR2xwHMk8CUACJYBJgH9MUekJBJ4J2ilCWvL1L+6t1Gwn4JCOQWKogbFnohaZtujwJFLh1pJC48ZS1XiV9dOQ==, tarball: file:projects/arm-eventgrid.tgz} name: '@rush-temp/arm-eventgrid' version: 0.0.0 dependencies: @@ -8832,13 +8817,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-eventhub.tgz: - resolution: {integrity: sha512-MNqGzCH0KHNhb9glqTIUDk71zsQho3XkP1YVS5uAdBHxG52vls0PyuN07mfJMSStuVPycEf1Rgk8zYW6Vx7F1w==, tarball: file:projects/arm-eventhub.tgz} + resolution: {integrity: sha512-xK9uI7V95KRG1FH7/xg4m+hHzZVxWBEm0WYMbkryPs2tMNgJXgZ6a+LrVdOyjShgMfhbe6w7TYHyo9UFDci5hA==, tarball: file:projects/arm-eventhub.tgz} name: '@rush-temp/arm-eventhub' version: 0.0.0 dependencies: @@ -8859,12 +8841,11 @@ packages: typescript: 4.2.4 uglify-js: 3.14.2 transitivePeerDependencies: - - debug - supports-color dev: false file:projects/arm-extendedlocation.tgz: - resolution: {integrity: sha512-WWytW03UCehYVkMeMjAg/vfkWLVx43lVnKaxuh22XgM/fLQ+m2ToJSCKVuUsGSKaT4/1DckjJiuRi5SM4Ikw9w==, tarball: file:projects/arm-extendedlocation.tgz} + resolution: {integrity: sha512-yQpzybX1YY1UBHRwPj+yqndMFqdONGLZuF1N3YIUIJlqbUkQKGVEEiVgxN0EmSDO58fHJBMwLMj75CPFG2WmOg==, tarball: file:projects/arm-extendedlocation.tgz} name: '@rush-temp/arm-extendedlocation' version: 0.0.0 dependencies: @@ -8882,9 +8863,6 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-features.tgz: @@ -8964,7 +8942,7 @@ packages: dev: false file:projects/arm-logic.tgz: - resolution: {integrity: sha512-TRPgd6No0PMNfFimmv9Pb/cKJUdPpPLQjcoaVw3hO060eBu0FaH8gqR7QstLP/pZz1yGu0o3XTmmZ3s/uSsnEQ==, tarball: file:projects/arm-logic.tgz} + resolution: {integrity: sha512-uoLg+ypMm6FmdfBx1ou2eGBuYGuIVdGjlNEnXeEBVRenmKcgwmrdb0bSTB6PiVN125U20FgpCb0YJDOgRuF/9w==, tarball: file:projects/arm-logic.tgz} name: '@rush-temp/arm-logic' version: 0.0.0 dependencies: @@ -8982,9 +8960,6 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-managedapplications.tgz: @@ -9007,7 +8982,7 @@ packages: dev: false file:projects/arm-mediaservices.tgz: - resolution: {integrity: sha512-3Umn8knfccMOuwf0O1zxyw39vW9u1wC4Yp43EmYmSHsu8a2pH4cp0bMepRo87OJeWIRtQERfKqrhBDv7N58CVQ==, tarball: file:projects/arm-mediaservices.tgz} + resolution: {integrity: sha512-yy6cdRD41ndTQfmklhmQgj12Wpv4ZxtoNQl7fWTrbHFE5ggWEjWzYVet4TB5ApbSCaUVcOtPStiIFBmdYUEZrw==, tarball: file:projects/arm-mediaservices.tgz} name: '@rush-temp/arm-mediaservices' version: 0.0.0 dependencies: @@ -9025,9 +9000,6 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-network.tgz: @@ -9055,7 +9027,7 @@ packages: dev: false file:projects/arm-notificationhubs.tgz: - resolution: {integrity: sha512-1ilWg8HCib1zaXp/krlNaus++YfONAG4MFe9OXA2Ls9V11SqAw4bJojGAUDYmhJrYqS5qekvp6fpPLBuAHPQEg==, tarball: file:projects/arm-notificationhubs.tgz} + resolution: {integrity: sha512-WaL7o4K3SAfEvfn6tUdEYKWeNaS37XC5/dkQfcsIjKD5Ou6ZU42jCQVGS9wb+oY5KT2A/RXSJYJpL9KJVRCUiA==, tarball: file:projects/arm-notificationhubs.tgz} name: '@rush-temp/arm-notificationhubs' version: 0.0.0 dependencies: @@ -9073,13 +9045,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-operationalinsights.tgz: - resolution: {integrity: sha512-d3Xg2pFxgav2I9VnkgVNvUsCURAWxK8w4J4drE2KS/tSNoW+TIDeHi24NBbYi+D3BuDJYta9oQOtBpdj9sO4+Q==, tarball: file:projects/arm-operationalinsights.tgz} + resolution: {integrity: sha512-6bdNT07tb4vKV3cfDCJEf1HLAdjLyomvgTqVgYMU2WpUEh1++rgjFJf7RGDbi/h2kLJ7ERYH5xUZFXcCyFoB/g==, tarball: file:projects/arm-operationalinsights.tgz} name: '@rush-temp/arm-operationalinsights' version: 0.0.0 dependencies: @@ -9097,13 +9066,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-operations.tgz: - resolution: {integrity: sha512-cVFq1i6MXVaKMU/DkYw2BM9lT7pTkv1pD/CeWW+sXO/IM5xLDBq2IhknP0PEdHH60RcfTt3EwoS4q9eUPlMKbw==, tarball: file:projects/arm-operations.tgz} + resolution: {integrity: sha512-bfQ2YR9KigdsOYK8YBti2REdvUP+3RlGDkmnlpITR/S4AJdAVHHhruvmikMDSPvi/W5po6xwE2vHKMBQIQKYlQ==, tarball: file:projects/arm-operations.tgz} name: '@rush-temp/arm-operations' version: 0.0.0 dependencies: @@ -9121,13 +9087,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-policy.tgz: - resolution: {integrity: sha512-7O/gYIgeBj6BnFxnLUmxWCdnsljPzs6XDy4NqM0RYlBRToxlIdV+Tn6TADE+ZkHM0tMBLTLVMj0LAHAHVnQO2g==, tarball: file:projects/arm-policy.tgz} + resolution: {integrity: sha512-qV+rEimyGpmAxdLaIKUU1NI1clVddBq6NaE6GbUfg+iXADJpRxGebkSzP6pcH2mWdNZrCBId462AxKzSQvXLEg==, tarball: file:projects/arm-policy.tgz} name: '@rush-temp/arm-policy' version: 0.0.0 dependencies: @@ -9145,13 +9108,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-postgresql.tgz: - resolution: {integrity: sha512-0ZtEKQb3+gBDpqcRCyIa0ap1PuKUz/55GgMWRbENPHJDUS/ONODyvKJH1kdyEpGTVUDIOKV0P4MK5DODX4n5OA==, tarball: file:projects/arm-postgresql.tgz} + resolution: {integrity: sha512-TNrzPPYJKsZw7LBRmtUub1nETEBquEs64tsgOpMLat88idB1Bbm7Z6jImYGEm+oMTIsiLWd0ASZAaT3nsKkY3A==, tarball: file:projects/arm-postgresql.tgz} name: '@rush-temp/arm-postgresql' version: 0.0.0 dependencies: @@ -9169,9 +9129,6 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-purview.tgz: @@ -9193,7 +9150,7 @@ packages: dev: false file:projects/arm-quota.tgz: - resolution: {integrity: sha512-SRpBEql0y3kdYMhc1tEuEKjQuLnvAhhXyH46MA6wynnJ6G7nPX886kGcTsUFlENVZ3rN3aT7CFmSlX8ytYg8hw==, tarball: file:projects/arm-quota.tgz} + resolution: {integrity: sha512-rtaLIQ4qnFja0VpqLPDIMDCulFopqMqIk5xCJmgbzYnE0abobPMp66qfu1lDK7ns/fEiLM3Ntfr/OtvYZDivBA==, tarball: file:projects/arm-quota.tgz} name: '@rush-temp/arm-quota' version: 0.0.0 dependencies: @@ -9211,13 +9168,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-recoveryservices.tgz: - resolution: {integrity: sha512-h96uDGJ2hS8JJrs8n4hiZk66Qn/B27mM125HLiELB+vZzkUiY2x8WdGU7/hIQjta6rF68p/vxfk5IeU7MxywCQ==, tarball: file:projects/arm-recoveryservices.tgz} + resolution: {integrity: sha512-PP8WcdwDjknzk3qnt5/qCg6HdbMGIqkIGJSp6tn4sdJns5ceLKwshYQ4/SI7omACeOFW+oriuYzjJnst6s15xQ==, tarball: file:projects/arm-recoveryservices.tgz} name: '@rush-temp/arm-recoveryservices' version: 0.0.0 dependencies: @@ -9235,13 +9189,10 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-rediscache.tgz: - resolution: {integrity: sha512-lxycTfI2J1fQKfUqMqJkoin1HXiLCR6JHpyQYG1uce815GRijebyNYo97vfq/e6XoWiubRlNxd6FHXSo2QHvbw==, tarball: file:projects/arm-rediscache.tgz} + resolution: {integrity: sha512-tz7W9ElsDyJVOyXZ3bEBZygn9/9Up4+ct470WAprZVgQdS39OI/HVZi4O1fOsLUn8YHYu8B5BHCFELzgqbQB2w==, tarball: file:projects/arm-rediscache.tgz} name: '@rush-temp/arm-rediscache' version: 0.0.0 dependencies: @@ -9261,7 +9212,6 @@ packages: typescript: 4.2.4 uglify-js: 3.14.2 transitivePeerDependencies: - - debug - supports-color dev: false @@ -9304,7 +9254,7 @@ packages: dev: false file:projects/arm-security.tgz: - resolution: {integrity: sha512-egPlM7UyYRlxRPUh63hKyk9SpAAmHf12i+GLBvBQJ+I3OQObAqnLckrgndYoc0lZEy95K70g57eXfQbtlNI3Pg==, tarball: file:projects/arm-security.tgz} + resolution: {integrity: sha512-H6aa5+i2bHOriVDn+PUCkK+41MEGxvUdTsROIVPid3VHe60jOeVVdyUrfclje0XeFUi5E4aQHZPECNYsz27A7w==, tarball: file:projects/arm-security.tgz} name: '@rush-temp/arm-security' version: 0.0.0 dependencies: @@ -9322,9 +9272,6 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-servicebus.tgz: @@ -9423,7 +9370,7 @@ packages: dev: false file:projects/arm-videoanalyzer.tgz: - resolution: {integrity: sha512-fxZzJ1MBtbFk1P55q5Lm/9mYbcnYlX3s1R/nOUrqeZy6Wsz62rvOge7Lxji+qeiaTFc5U3i/JojuWnJsH1RrQg==, tarball: file:projects/arm-videoanalyzer.tgz} + resolution: {integrity: sha512-85e/n7OPI5a3aJ4G7QuGI/q0ezQ+2wH6hySHj1oplCEvz6Lfvz2nEwfsQzXPjzxoIjhn/wrd/D0B0ah5M06HwQ==, tarball: file:projects/arm-videoanalyzer.tgz} name: '@rush-temp/arm-videoanalyzer' version: 0.0.0 dependencies: @@ -9441,9 +9388,6 @@ packages: tslib: 2.3.1 typescript: 4.2.4 uglify-js: 3.14.2 - transitivePeerDependencies: - - debug - - supports-color dev: false file:projects/arm-webpubsub.tgz: @@ -9523,6 +9467,67 @@ packages: - utf-8-validate dev: false + file:projects/communication-calling-server.tgz: + resolution: {integrity: sha512-SQvB6xtrPhfBh8ZZA8layFfs99kzeggQldTOVerkotaPKqii35uYes2VpUd8Np/zh7Xkn5ehtscX5oxDWt1Qcw==, tarball: file:projects/communication-calling-server.tgz} + name: '@rush-temp/communication-calling-server' + version: 0.0.0 + dependencies: + '@azure/communication-identity': 1.0.0 + '@azure/core-tracing': 1.0.0-preview.13 + '@azure/identity': 2.0.0-beta.6 + '@microsoft/api-extractor': 7.7.11 + '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 + '@rollup/plugin-json': 4.1.0_rollup@1.32.1 + '@rollup/plugin-multi-entry': 3.0.1_rollup@1.32.1 + '@rollup/plugin-node-resolve': 8.4.0_rollup@1.32.1 + '@rollup/plugin-replace': 2.4.2_rollup@1.32.1 + '@types/chai': 4.2.22 + '@types/mocha': 7.0.2 + '@types/node': 12.20.36 + '@types/node-fetch': 2.5.12 + '@types/sinon': 9.0.11 + '@types/uuid': 8.3.1 + assert: 1.5.0 + chai: 4.3.4 + cross-env: 7.0.3 + dotenv: 8.6.0 + eslint: 7.32.0 + events: 3.3.0 + inherits: 2.0.4 + karma: 6.3.6 + karma-chrome-launcher: 3.1.0 + karma-coverage: 2.0.3 + karma-edge-launcher: 0.4.2_karma@6.3.6 + karma-env-preprocessor: 0.1.1 + karma-firefox-launcher: 1.3.0 + karma-ie-launcher: 1.0.0_karma@6.3.6 + karma-junit-reporter: 2.0.1_karma@6.3.6 + karma-mocha: 2.0.1 + karma-mocha-reporter: 2.2.5_karma@6.3.6 + karma-sourcemap-loader: 0.3.8 + mocha: 7.2.0 + mocha-junit-reporter: 1.23.3_mocha@7.2.0 + nyc: 14.1.1 + prettier: 1.19.1 + rimraf: 3.0.2 + rollup: 1.32.1 + rollup-plugin-shim: 1.0.0 + rollup-plugin-sourcemaps: 0.4.2_rollup@1.32.1 + rollup-plugin-terser: 5.3.1_rollup@1.32.1 + rollup-plugin-visualizer: 4.2.2_rollup@1.32.1 + sinon: 9.2.4 + tslib: 2.3.1 + typedoc: 0.15.2 + typescript: 4.2.4 + util: 0.12.4 + uuid: 8.3.2 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + dev: false + file:projects/communication-chat.tgz: resolution: {integrity: sha512-3mBDemL2PvS7+J1J+I6rvF0FDpoN5BKfpISDGwz+7vbCTKOBa1Wrnp6OfdaXyT7clZ0vTdzAxbz0JN/MdWnM7w==, tarball: file:projects/communication-chat.tgz} name: '@rush-temp/communication-chat' @@ -12086,7 +12091,7 @@ packages: dev: false file:projects/perf-identity.tgz: - resolution: {integrity: sha512-+UNCBUAaO2bDZ4ua5tpd+PzUMrNOcb8IYEQxHI34hX3zpdFkYz7xxVNgH8EPxFMgjrvQ8J3efMs5+jfXQteVJg==, tarball: file:projects/perf-identity.tgz} + resolution: {integrity: sha512-+TzLPzctMFjD//ZUKtAVNm19LxoszSzNd/r6j3MGPJN9Wzm88Ie2VGM9A0bCf7ngVPBFJQhR1geQ2w3N45proQ==, tarball: file:projects/perf-identity.tgz} name: '@rush-temp/perf-identity' version: 0.0.0 dependencies: diff --git a/rush.json b/rush.json index c6d6cbd7934b..6539c6780add 100644 --- a/rush.json +++ b/rush.json @@ -401,6 +401,11 @@ "projectFolder": "sdk/quantum/quantum-jobs", "versionPolicyName": "client" }, + { + "packageName": "@azure/communication-calling-server", + "projectFolder": "sdk/communication/communication-calling-server", + "versionPolicyName": "client" + }, { "packageName": "@azure/communication-chat", "projectFolder": "sdk/communication/communication-chat", @@ -1042,4 +1047,4 @@ "versionPolicyName": "management" } ] -} \ No newline at end of file +} diff --git a/sdk/communication/ci.yml b/sdk/communication/ci.yml index 0a47278faf45..a7bf5b9bf256 100644 --- a/sdk/communication/ci.yml +++ b/sdk/communication/ci.yml @@ -26,6 +26,8 @@ extends: parameters: ServiceDirectory: communication Artifacts: + - name: azure-communication-calling-server + safeName: azurecommunicationcallingserver - name: azure-communication-common safeName: azurecommunicationcommon - name: azure-communication-sms diff --git a/sdk/communication/communication-calling-server/.nycrc b/sdk/communication/communication-calling-server/.nycrc new file mode 100644 index 000000000000..5842dfe9ce89 --- /dev/null +++ b/sdk/communication/communication-calling-server/.nycrc @@ -0,0 +1,14 @@ +{ + "include": ["dist-esm/src/**/*.js"], + "exclude": [ + "**/*.d.ts", + "dist-esm/src/generated/*", + "dist-esm/src/RepeatableContentDownloadResponse.browser.js" + ], + "reporter": ["text-summary", "html", "cobertura"], + "exclude-after-remap": false, + "sourceMap": true, + "produce-source-map": true, + "instrument": true, + "all": true +} diff --git a/sdk/communication/communication-calling-server/CHANGELOG.md b/sdk/communication/communication-calling-server/CHANGELOG.md new file mode 100644 index 000000000000..7edf92942d6e --- /dev/null +++ b/sdk/communication/communication-calling-server/CHANGELOG.md @@ -0,0 +1,9 @@ +# Release History +## 1.0.0-beta.1 (2021-12-15) + +The first preview of the Azure Communication CallingServer Client has the following features: + +- create/get/update/delete a call +- add participants +- start/stop/pause/resume a recording of the call +- download the recording content \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/LICENSE b/sdk/communication/communication-calling-server/LICENSE new file mode 100644 index 000000000000..ea8fb1516028 --- /dev/null +++ b/sdk/communication/communication-calling-server/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/sdk/communication/communication-calling-server/README.md b/sdk/communication/communication-calling-server/README.md new file mode 100644 index 000000000000..b65706795b72 --- /dev/null +++ b/sdk/communication/communication-calling-server/README.md @@ -0,0 +1,106 @@ +# Azure Communication CallingServer client library for JavaScript + +This package contains a JavaScript SDK for Azure Communication Services for CallingServer. +Read more about Azure Communication Services [here](https://docs.microsoft.com/azure/communication-services/overview) + +[Source code](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/communication/communication-calling-server) + +## Getting started + +### Prerequisites + +- An [Azure subscription][azure_sub]. +- An existing Communication Services resource. If you need to create the resource, you can use the [Azure Portal][azure_portal], the [Azure PowerShell][azure_powershell], or the [Azure CLI][azure_cli]. + +- A deployed Communication Services resource. You can use the [Azure Portal](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource?tabs=windows&pivots=platform-azp) or the [Azure PowerShell](https://docs.microsoft.com/powershell/module/az.communication/new-azcommunicationservice) to set it up. +- You must have a phone number configured that is associated with an Azure subscription + +### Installing + +```bash +npm install @azure/communication-calling-server +``` + +### Browser support + +#### JavaScript Bundle + +To use this client library in the browser, first you need to use a bundler. For details on how to do this, please refer to our [bundling documentation](https://aka.ms/AzureSDKBundling). +In `rollup.config.js`, add following customized name exports in `cjs` plugin. + +```JavaScript + +cjs({ + namedExports: { + events: ["EventEmitter"], + "@azure/communication-signaling": ["CommunicationSignalingClient", "SignalingClient"], + "@opentelemetry/api": ["CanonicalCode", "SpanKind", "TraceFlags"] + } +}) + +``` + +## Key concepts + +`CallingServerClient` provides the functionality to make call connection, join call connection or initialize a server call. + +## Examples + +The following section provides several code snippets covering some of the most common Azure Communication Services tasks, including: + +- [Client Initialization](#client-initialization) +- [Make a call to a phone number recipient](#make-a-call-to-a-phone-number-recipient) + +### Client Initialization + +To initialize the CallingServer Client, the connection string can be used to instantiate. + +```typescript +import { CallingServerClient } from "@azure/communication-calling-server"; + +const connectionString = `endpoint=https://.communication.azure.com/;accessKey=`; +const client = new CallingServerClient(connectionString); +``` + +### Make a call to a phone number recipient + +Once the client is initialized, the `createCallConnection` method can be invoked: + +```typescript +import { CreateCallOptions } from "@azure/communication-calling-server"; + +const createCallResponse = callingserver_client.createCallConnection( + (source = ""), + (targets = ""), + (createCallOptions = Something) +); +``` + +- `from_`: Something. +- `to`: Something. +- `createCallOptions`: Something. + +## Troubleshooting + +Running into issues? This section should contain details as to what to do there. + +## Next steps + +More sample code should go [here](https://github.com/Azure/azure-sdk-for-js), along with links out to the appropriate example tests. + +## Provide Feedback + +If you encounter any bugs or have suggestions, please file an issue in the [Issues](https://github.com/Azure/azure-sdk-for-js/issues) section of the project + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the +PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + + diff --git a/sdk/communication/communication-calling-server/api-extractor.json b/sdk/communication/communication-calling-server/api-extractor.json new file mode 100644 index 000000000000..443b3cbe0d42 --- /dev/null +++ b/sdk/communication/communication-calling-server/api-extractor.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "mainEntryPointFilePath": "types/src/index.d.ts", + "docModel": { + "enabled": true + }, + "apiReport": { + "enabled": true, + "reportFolder": "./review" + }, + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "", + "publicTrimmedFilePath": "./types/communication-calling-server.d.ts" + }, + "messages": { + "tsdocMessageReporting": { + "default": { + "logLevel": "none" + } + }, + "extractorMessageReporting": { + "ae-missing-release-tag": { + "logLevel": "none" + }, + "ae-unresolved-link": { + "logLevel": "none" + } + } + } +} diff --git a/sdk/communication/communication-calling-server/karma.conf.js b/sdk/communication/communication-calling-server/karma.conf.js new file mode 100644 index 000000000000..eb70e227cdd0 --- /dev/null +++ b/sdk/communication/communication-calling-server/karma.conf.js @@ -0,0 +1,142 @@ +// https://github.com/karma-runner/karma-chrome-launcher +process.env.CHROME_BIN = require("puppeteer").executablePath(); +require("dotenv").config(); +const { + jsonRecordingFilterFunction, + isPlaybackMode, + isSoftRecordMode, + isRecordMode +} = require("@azure-tools/test-recorder"); + +module.exports = function(config) { + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: "./", + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ["mocha"], + + plugins: [ + "karma-mocha", + "karma-mocha-reporter", + "karma-chrome-launcher", + "karma-edge-launcher", + "karma-firefox-launcher", + "karma-ie-launcher", + "karma-env-preprocessor", + "karma-coverage", + "karma-sourcemap-loader", + "karma-junit-reporter", + "karma-json-to-file-reporter", + "karma-json-preprocessor" + ], + + // list of files / patterns to load in the browser + files: ["dist-test/index.browser.js"].concat( + isPlaybackMode() || isSoftRecordMode() ? ["recordings/browsers/**/*.json"] : [] + ), + + // list of files / patterns to exclude + exclude: [], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + "**/*.js": ["sourcemap", "env"], + "recordings/browsers/**/*.json": ["json"] + // IMPORTANT: COMMENT following line if you want to debug in your browsers!! + // Preprocess source file to calculate code coverage, however this will make source file unreadable + //"dist-test/index.browser.js": ["coverage"] + }, + + // inject following environment values into browser testing with window.__env__ + // environment values MUST be exported or set with same console running "karma start" + // https://www.npmjs.com/package/karma-env-preprocessor + envPreprocessor: [ + "TEST_MODE", + "AZURE_PHONE_NUMBER", + "COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING", + "BASE_URL" + ], + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ["mocha", "coverage", "junit", "json-to-file"], + + coverageReporter: { + // specify a common output directory + dir: "coverage-browser/", + reporters: [ + { type: "json", subdir: ".", file: "coverage.json" }, + { type: "lcovonly", subdir: ".", file: "lcov.info" }, + { type: "html", subdir: "html" }, + { type: "cobertura", subdir: ".", file: "cobertura-coverage.xml" } + ] + }, + + junitReporter: { + outputDir: "", // results will be saved as $outputDir/$browserName.xml + outputFile: "test-results.browser.xml", // if included, results will be saved as $outputDir/$browserName/$outputFile + suite: "", // suite will become the package name attribute in xml testsuite element + useBrowserName: false, // add browser name to report and classes names + nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element + classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element + properties: {} // key value pair of properties to add to the section of the report + }, + + jsonToFileReporter: { + filter: jsonRecordingFilterFunction, + outputPath: "." + }, + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + // 'ChromeHeadless', 'Chrome', 'Firefox', 'Edge', 'IE' + browsers: ["HeadlessChrome"], + + customLaunchers: { + HeadlessChrome: { + base: "ChromeHeadless", + flags: ["--no-sandbox", "--disable-web-security"] + } + }, + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: 1, + + browserNoActivityTimeout: 600000, + browserDisconnectTimeout: 10000, + browserDisconnectTolerance: 3, + browserConsoleLogOptions: { + terminal: !isRecordMode() + }, + + client: { + mocha: { + // change Karma's debug.html to the mocha web reporter + reporter: "html", + timeout: "600000" + } + } + }); +}; diff --git a/sdk/communication/communication-calling-server/package.json b/sdk/communication/communication-calling-server/package.json new file mode 100644 index 000000000000..8741e5a47e25 --- /dev/null +++ b/sdk/communication/communication-calling-server/package.json @@ -0,0 +1,158 @@ +{ + "name": "@azure/communication-calling-server", + "version": "1.0.0-beta.1", + "description": "SDK for Azure Communication CallingServer service.", + "sdk-type": "client", + "main": "dist/index.js", + "module": "dist-esm/src/index.js", + "browser": { + "stream": "./node_modules/stream-browserify/index.js", + "./dist-esm/src/credentials/cryptoUtils.js": "./dist-esm/src/credentials/cryptoUtils.browser.js", + "./dist-esm/src/RepeatableContentDownloadResponse.js": "./dist-esm/src/RepeatableContentDownloadResponse.browser.js", + "./dist-esm/test/public/utils/index.js": "./dist-esm/test/public/utils/index.browser.js" + }, + "types": "types/communication-calling-server.d.ts", + "scripts": { + "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", + "build:autorest": "autorest ./swagger/README.md --typescript --v3 && rushx format", + "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", + "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1", + "build:samples": "dev-tool samples publish --force", + "build:test": "tsc -p . && rollup -c rollup.test.config.js 2>&1", + "build": "tsc -p . && rollup -c 2>&1 && api-extractor run --local", + "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"", + "clean": "rimraf dist dist-* temp types *.tgz *.log", + "execute:samples": "dev-tool samples run samples-dev", + "extract-api": "tsc -p . && api-extractor run --local", + "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"", + "integration-test:browser": "karma start --single-run", + "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --full-trace -t 300000 \"dist-esm/test/public/*.spec.js\" \"dist-esm/test/public/node/*.spec.js\" \"dist-esm/test/internal/*.spec.js\" \"dist-esm/test/internal/node/*.spec.js\"", + "integration-test": "npm run integration-test:node && npm run integration-test:browser", + "lint:fix": "eslint package.json api-extractor.json src test --ext .ts --fix --fix-type [problem,suggestion]", + "lint": "eslint package.json api-extractor.json src test --ext .ts", + "pack": "npm pack 2>&1", + "prebuild": "npm run clean", + "test:browser": "npm run build:test && npm run unit-test:browser && npm run integration-test:browser", + "test:node": "npm run build:test && npm run unit-test:node && npm run integration-test:node", + "test": "npm run clean && npm run build:test && npm run unit-test", + "unit-test:browser": "karma start --single-run", + "unit-test:node": "mocha --reporter ../../../common/tools/mocha-multi-reporter.js dist-test/index.node.js", + "unit-test": "npm run unit-test:node && npm run unit-test:browser", + "docs": "typedoc --excludePrivate --excludeNotExported --excludeExternals --stripInternal --mode file --out ./dist/docs ./src" + }, + "files": [ + "dist/", + "dist-esm/src", + "types/communication-calling-server.d.ts", + "README.md", + "LICENSE" + ], + "repository": "github:Azure/azure-sdk-for-js", + "keywords": [ + "azure", + "cloud", + "Azure", + "communication", + "callingserver" + ], + "author": "Microsoft Corporation", + "license": "MIT", + "bugs": { + "url": "https://github.com/Azure/azure-sdk-for-js/issues" + }, + "engines": { + "node": ">=12.0.0" + }, + "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/communication/communication-calling-server/", + "sideEffects": false, + "prettier": "@azure/eslint-plugin-azure-sdk/prettier.json", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/communication-common": "^1.1.1", + "@azure/core-auth": "^1.3.0", + "@azure/core-http": "^2.0.0", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/logger": "^1.0.0", + "events": "^3.0.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/communication-identity": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/identity": "2.0.0-beta.6", + "@azure/test-utils": "^1.0.0", + "@azure-tools/test-recorder": "^1.0.0", + "@microsoft/api-extractor": "7.7.11", + "@rollup/plugin-commonjs": "11.0.2", + "@rollup/plugin-json": "^4.0.0", + "@rollup/plugin-multi-entry": "^3.0.0", + "@rollup/plugin-node-resolve": "^8.0.0", + "@rollup/plugin-replace": "^2.2.0", + "@types/chai": "^4.1.6", + "@types/mocha": "^7.0.2", + "@types/node": "^12.0.0", + "@types/node-fetch": "^2.5.0", + "@types/sinon": "^9.0.4", + "@types/uuid": "^8.0.0", + "assert": "^1.4.1", + "chai": "^4.2.0", + "cross-env": "^7.0.2", + "dotenv": "^8.2.0", + "eslint": "^7.15.0", + "inherits": "^2.0.3", + "karma-chrome-launcher": "^3.0.0", + "karma-coverage": "^2.0.0", + "karma-edge-launcher": "^0.4.2", + "karma-env-preprocessor": "^0.1.1", + "karma-firefox-launcher": "^1.1.0", + "karma-ie-launcher": "^1.0.0", + "karma-junit-reporter": "^2.0.1", + "karma-mocha-reporter": "^2.2.5", + "karma-mocha": "^2.0.1", + "karma-sourcemap-loader": "^0.3.8", + "karma": "^6.2.0", + "mocha-junit-reporter": "^1.18.0", + "mocha": "^7.1.1", + "nyc": "^14.0.0", + "prettier": "^1.16.4", + "rimraf": "^3.0.0", + "rollup-plugin-sourcemaps": "^0.4.2", + "rollup-plugin-terser": "^5.1.1", + "rollup-plugin-visualizer": "^4.0.4", + "rollup-plugin-shim": "^1.0.0", + "rollup": "^1.16.3", + "sinon": "^9.0.2", + "typescript": "~4.2.0", + "util": "^0.12.1", + "typedoc": "0.15.2", + "tslib": "^2.2.0" + }, + "//metadata": { + "constantPaths": [ + { + "path": "src/generated/src/callingserverApiClientContext.ts", + "prefix": "packageVersion" + }, + { + "path": "src/constants.ts", + "prefix": "SDK_VERSION" + }, + { + "path": "swagger/README.md", + "prefix": "package-version" + } + ] + }, + "//sampleConfiguration": { + "productName": "Azure Communication Services - CallingServer", + "productSlugs": [ + "azure", + "azure-communication-services" + ], + "requiredResources": { + "Azure Communication Services account": "https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource" + } + } +} diff --git a/sdk/communication/communication-calling-server/recordings/browsers/call_connection_live_test_call_automation_operations/recording_run_create_play_cancel_hangup_scenario.json b/sdk/communication/communication-calling-server/recordings/browsers/call_connection_live_test_call_automation_operations/recording_run_create_play_cancel_hangup_scenario.json new file mode 100644 index 000000000000..6ea1ed977298 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/call_connection_live_test_call_automation_operations/recording_run_create_play_cancel_hangup_scenario.json @@ -0,0 +1,110 @@ +{ + "recordings": [ + { + "method": "POST", + "url": "https://endpoint/identities", + "query": { + "api-version": "2021-03-07" + }, + "requestBody": null, + "status": 201, + "response": "{\"identity\":{\"id\":\"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_0000000d-84b0-c2ed-ab49-094822000e9e\"}}", + "responseHeaders": { + "api-supported-versions": "2020-07-20-preview2, 2021-02-22-preview1, 2021-03-07, 2021-03-31-preview1, 2021-10-31-preview", + "content-length": "101", + "content-type": "application/json; charset=utf-8", + "date": "Wed, 03 Nov 2021 07:59:11 GMT", + "ms-cv": "ubJ+Qp6SUkGPRJz6PJTdmw.0", + "request-context": "appId=", + "strict-transport-security": "max-age=2592000", + "x-azure-ref": "0T0GCYQAAAAD2RwDvWBWyRpQwKpccj+7OV1NURURHRTA4MTcAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-ms-client-request-id": "5bbe36ee-1fc5-423f-baf8-6607816875df", + "x-processing-time": "23ms" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/callConnections", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": "{\"alternateCallerId\":{\"value\":\"+18445764430\"},\"targets\":[{\"phoneNumber\":{\"value\":\"+15551234567\"}}],\"source\":{\"communicationUser\":{\"id\":\"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_0000000d-84b0-c2ed-ab49-094822000e9e\"}},\"callbackUri\":\"https://endpoint/callback\",\"requestedMediaTypes\":[\"audio\"],\"requestedCallEvents\":[\"participantsUpdated\",\"toneReceived\"]}", + "status": 201, + "response": "{\"callConnectionId\":\"b91f1300-a37c-4818-81e7-3eb580b21737\"}", + "responseHeaders": { + "content-length": "59", + "content-type": "application/json; charset=utf-8", + "date": "Wed, 03 Nov 2021 07:59:12 GMT", + "x-azure-ref": "0T0GCYQAAAAAt62bir6IMSJLnLVER8WHHV1NURURHRTA4MTcAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "39f0dd1a-fd2c-4a15-bd7e-325b22bf9b30", + "x-ms-client-request-id": "4395ab4f-6468-4f25-9f1e-cf747f4ff069" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/callConnections/b91f1300-a37c-4818-81e7-3eb580b21737/:playAudio", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": "{\"audioFileUri\":\"https://endpoint/audio/sample-message.wav\",\"loop\":true,\"operationContext\":\"operationContext163592635267500973\",\"audioFileId\":\"audioFileId163592635267507416\",\"callbackUri\":\"https://endpoint/callback\"}", + "status": 202, + "response": "{\"operationId\":\"a63348ce-41b3-47d1-ac09-3dbe20792785\",\"status\":\"running\",\"operationContext\":\"operationContext163592635267500973\"}", + "responseHeaders": { + "content-length": "129", + "content-type": "application/json; charset=utf-8", + "date": "Wed, 03 Nov 2021 07:59:22 GMT", + "x-azure-ref": "0WkGCYQAAAAB/wLJe91cqRKuHjMKAmExSV1NURURHRTA4MTcAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "de3e5959-fcf4-4dd6-8b16-0b9e05e61051", + "x-ms-client-request-id": "af703621-4657-4975-8188-b3df69bdfa85" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/callConnections/b91f1300-a37c-4818-81e7-3eb580b21737/:cancelAllMediaOperations", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 200, + "response": "{\"operationId\":\"dd708f21-4817-4eab-a164-f80880337c52\",\"status\":\"completed\"}", + "responseHeaders": { + "content-length": "75", + "content-type": "application/json; charset=utf-8", + "date": "Wed, 03 Nov 2021 07:59:23 GMT", + "x-azure-ref": "0W0GCYQAAAADVDnXAr0dtTIrE5KFyq9pOV1NURURHRTA4MTcAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "139c5f9b-9bdf-4453-856d-d7b95d640837", + "x-ms-client-request-id": "19c13571-6261-4def-b0ac-d71bf84bebdd" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/callConnections/b91f1300-a37c-4818-81e7-3eb580b21737/:hangup", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Wed, 03 Nov 2021 07:59:33 GMT", + "x-azure-ref": "0ZUGCYQAAAABXuEMqf1qlQazZAB836yq3V1NURURHRTA4MTcAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "66550ba0-9d16-425a-8df5-ffc739bf9e2f", + "x-ms-client-request-id": "3b32b432-253f-42ad-80b9-c48b389c63fc" + } + } + ], + "uniqueTestInfo": { + "uniqueName": { + "audioFileId": "audioFileId163592635267507416", + "operationContext": "operationContext163592635267500973" + }, + "newDate": {} + }, + "hash": "c37e0573593c63b00d076fd407c725d0" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_delete.json b/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_delete.json new file mode 100644 index 000000000000..32931dae0f85 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_delete.json @@ -0,0 +1,23 @@ +{ + "recordings": [ + { + "method": "DELETE", + "url": "https://endpoint/v1/objects/0-wus-d6-fdf8ff0fdcd668bca8c52c0b1ee79b05", + "query": {}, + "requestBody": null, + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 17:49:08 GMT", + "server": "Microsoft-HTTPAPI/2.0", + "strict-transport-security": "max-age=31536000; includeSubDomains" + } + } + ], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "e810745688333ce018b48166e9e854e3" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_invalid_file_delete.json b/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_invalid_file_delete.json new file mode 100644 index 000000000000..97de0a6c7512 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_invalid_file_delete.json @@ -0,0 +1,23 @@ +{ + "recordings": [ + { + "method": "GET", + "url": "https://endpoint/v1/objects/0-wus-d4-ca4017a32f8514aa9f054f0917270000", + "query": {}, + "requestBody": null, + "status": 404, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 17:47:04 GMT", + "server": "Microsoft-HTTPAPI/2.0", + "strict-transport-security": "max-age=31536000; includeSubDomains" + } + } + ], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "a29d365489ae98459d067c46c720becc" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_unauthorized_delete.json b/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_unauthorized_delete.json new file mode 100644 index 000000000000..0a8d608ae5ee --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/delete_live_tests/recording_unauthorized_delete.json @@ -0,0 +1,23 @@ +{ + "recordings": [ + { + "method": "DELETE", + "url": "https://endpoint/v1/objects/0-wus-d6-fdf8ff0fdcd668bca8c52c0b1ee79b05", + "query": {}, + "requestBody": null, + "status": 401, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 17:47:04 GMT", + "server": "Microsoft-HTTPAPI/2.0", + "strict-transport-security": "max-age=31536000; includeSubDomains" + } + } + ], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "1b018902befb4c128b53cbe8d7af4a82" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_download.json b/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_download.json new file mode 100644 index 000000000000..ffd25ce5eadf --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_download.json @@ -0,0 +1,26 @@ +{ + "recordings": [ + { + "method": "GET", + "url": "https://endpoint/v1/objects/0-eus-d15-af5689148b0afa252a57a0121b744dcd/content/acsmetadata", + "query": {}, + "requestBody": null, + "status": 200, + "response": "{\r\n \"chunkDocumentId\": \"0-eus-d15-af5689148b0afa252a57a0121b744dcd\"\r\n}", + "responseHeaders": { + "cache-control": "no-cache, max-age=0, s-maxage=0, private", + "content-length": "65", + "content-range": "bytes 0-64/65", + "content-type": "application/octet-stream", + "date": "Thu, 14 Oct 2021 23:40:58 GMT", + "server": "Microsoft-HTTPAPI/2.0", + "strict-transport-security": "max-age=31536000; includeSubDomains" + } + } + ], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "72a047668641841240c24ee9c374c387" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_download_with_redirection.json b/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_download_with_redirection.json new file mode 100644 index 000000000000..6a36e66404c0 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_download_with_redirection.json @@ -0,0 +1,26 @@ +{ + "recordings": [ + { + "method": "GET", + "url": "https://endpoint/v1/objects/0-sa-d4-a29f0c0212c0a2a634ab078245184de8/content/acsmetadata", + "query": {}, + "requestBody": null, + "status": 200, + "response": "{\r\n \"chunkDocumentId\": \"0-sa-d4-a29f0c0212c0a2a634ab078245184de8\"\r\n}", + "responseHeaders": { + "cache-control": "no-cache, max-age=0, s-maxage=0, private", + "content-length": "62", + "content-range": "bytes 0-61/62", + "content-type": "application/octet-stream", + "date": "Thu, 14 Oct 2021 23:48:30 GMT", + "server": "Microsoft-HTTPAPI/2.0", + "strict-transport-security": "max-age=31536000; includeSubDomains" + } + } + ], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "7086d64cd74997887e2fe4e73ad0a5f0" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_unauthorized_download.json b/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_unauthorized_download.json new file mode 100644 index 000000000000..813b13a21461 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/download_content/recording_unauthorized_download.json @@ -0,0 +1,23 @@ +{ + "recordings": [ + { + "method": "GET", + "url": "https://endpoint/v1/objects/0-eus-d15-af5689148b0afa252a57a0121b744dcd/content/acsmetadata", + "query": {}, + "requestBody": null, + "status": 401, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Thu, 14 Oct 2021 23:05:06 GMT", + "server": "Microsoft-HTTPAPI/2.0", + "strict-transport-security": "max-age=31536000; includeSubDomains" + } + } + ], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "7711f7a1c25e2565db804c3a1cc1b04a" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/browsers/server_call_live_test_recording_operations/recording_run_all_client_recording_operations.json b/sdk/communication/communication-calling-server/recordings/browsers/server_call_live_test_recording_operations/recording_run_all_client_recording_operations.json new file mode 100644 index 000000000000..e884f0061fa7 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/browsers/server_call_live_test_recording_operations/recording_run_all_client_recording_operations.json @@ -0,0 +1,213 @@ +{ + "recordings": [ + { + "method": "POST", + "url": "https://endpoint/calling:join", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": "{\"callLocator\":{\"groupCallId\":\"31fccfc0-d804-5e92-9d9e-900b7b3eb6cc\",\"kind\":\"groupCallLocator\"},\"source\":{\"communicationUser\":{\"id\":\"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_6f8c191d-f701-58b7-a744-35bac2a8f074\"}},\"callbackUri\":\"https://endpoint/callback\",\"requestedMediaTypes\":[\"audio\"],\"requestedCallEvents\":[\"participantsUpdated\"]}", + "status": 202, + "response": "{\"callConnectionId\":\"c51f1300-9c7f-47f3-a9ad-fe7a135c7abf\"}", + "responseHeaders": { + "content-length": "59", + "content-type": "application/json; charset=utf-8", + "date": "Tue, 02 Nov 2021 19:42:18 GMT", + "x-azure-ref": "0mZSBYQAAAAAYvQ+BB5CmQK7YCbqAO+/4V1NURURHRTA4MDgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "f0a183d0-2ff8-4ef5-ba9b-01410494f48b", + "x-ms-client-request-id": "95b6ea34-4042-405d-b06c-ae0810d56ae6" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling:join", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": "{\"callLocator\":{\"groupCallId\":\"31fccfc0-d804-5e92-9d9e-900b7b3eb6cc\",\"kind\":\"groupCallLocator\"},\"source\":{\"communicationUser\":{\"id\":\"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_ff23b678-5b97-564d-b6c4-6bb53068c498\"}},\"callbackUri\":\"https://endpoint/callback\",\"requestedMediaTypes\":[\"audio\"],\"requestedCallEvents\":[\"participantsUpdated\"]}", + "status": 202, + "response": "{\"callConnectionId\":\"c51f1300-1520-4845-bd29-f6002ad7fb0b\"}", + "responseHeaders": { + "content-length": "59", + "content-type": "application/json; charset=utf-8", + "date": "Tue, 02 Nov 2021 19:42:19 GMT", + "x-azure-ref": "0m5SBYQAAAACYjRand2fASaZcwMgvO2isV1NURURHRTA4MDgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "b57aeca9-e1e2-4601-a279-ff9ad5668a96", + "x-ms-client-request-id": "ddbec267-fce0-46f3-a4e2-94d00896d74a" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/recordings", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": "{\"callLocator\":{\"groupCallId\":\"31fccfc0-d804-5e92-9d9e-900b7b3eb6cc\",\"kind\":\"groupCallLocator\"},\"recordingStateCallbackUri\":\"https://endpoint/callback\"}", + "status": 200, + "response": "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiJjNTFmMTMwMC1jODZmLTQ2M2UtOWEzMi1jMTBjZTgzZDhmNjciLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI1YTMyMmNhNi1hOWI4LTQ1ZWEtYTJiMi00MWQ4MjlhODc4YmIifQ\"}", + "responseHeaders": { + "content-length": "180", + "content-type": "application/json; charset=utf-8", + "date": "Tue, 02 Nov 2021 19:42:25 GMT", + "x-azure-ref": "0m5SBYQAAAABPMh8+ahNwQqOzXyf7xo29V1NURURHRTA4MDgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "17a54790-abfe-4b74-ad2e-e833a73bda05", + "x-ms-client-request-id": "f3fa2c72-d928-40de-a4e8-74fbc9cb6c66" + } + }, + { + "method": "GET", + "url": "https://endpoint/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiJjNTFmMTMwMC1jODZmLTQ2M2UtOWEzMi1jMTBjZTgzZDhmNjciLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI1YTMyMmNhNi1hOWI4LTQ1ZWEtYTJiMi00MWQ4MjlhODc4YmIifQ", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 200, + "response": "{\"recordingState\":\"active\"}", + "responseHeaders": { + "content-length": "27", + "content-type": "application/json; charset=utf-8", + "date": "Tue, 02 Nov 2021 19:42:40 GMT", + "x-azure-ref": "0sZSBYQAAAABRa9LN2IPaR7FOvczllXSBV1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "d922b2f8-55e3-4403-be4b-885f85c24836", + "x-ms-client-request-id": "91bcfc86-0273-4e5f-865c-7dda92adbc95" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiJjNTFmMTMwMC1jODZmLTQ2M2UtOWEzMi1jMTBjZTgzZDhmNjciLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI1YTMyMmNhNi1hOWI4LTQ1ZWEtYTJiMi00MWQ4MjlhODc4YmIifQ/:pause", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 19:42:41 GMT", + "x-azure-ref": "0sZSBYQAAAAAo2dFt+dnwTLAnTclsJvW9V1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "8d449bb6-8813-4d9c-8d83-bc87a4b43ef0", + "x-ms-client-request-id": "6c1a4e71-042a-4602-8357-bfa117aecb02" + } + }, + { + "method": "GET", + "url": "https://endpoint/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiJjNTFmMTMwMC1jODZmLTQ2M2UtOWEzMi1jMTBjZTgzZDhmNjciLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI1YTMyMmNhNi1hOWI4LTQ1ZWEtYTJiMi00MWQ4MjlhODc4YmIifQ", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 200, + "response": "{\"recordingState\":\"inactive\"}", + "responseHeaders": { + "content-length": "29", + "content-type": "application/json; charset=utf-8", + "date": "Tue, 02 Nov 2021 19:42:51 GMT", + "x-azure-ref": "0vJSBYQAAAADkGWWrabQCQqdiGpmHwcGpV1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "bf0b6aca-a438-4947-a41e-2ebafbda7ec4", + "x-ms-client-request-id": "dbf40a88-1385-4e2f-ba12-fe7ec1d4003e" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiJjNTFmMTMwMC1jODZmLTQ2M2UtOWEzMi1jMTBjZTgzZDhmNjciLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI1YTMyMmNhNi1hOWI4LTQ1ZWEtYTJiMi00MWQ4MjlhODc4YmIifQ/:resume", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 19:42:51 GMT", + "x-azure-ref": "0vJSBYQAAAADznCC16DdlR5YARnu+CEACV1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "ce79b3df-93c8-4628-8feb-2961c33eae71", + "x-ms-client-request-id": "f1f515d8-3a45-4d8b-be85-bdd25d40d34f" + } + }, + { + "method": "GET", + "url": "https://endpoint/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiJjNTFmMTMwMC1jODZmLTQ2M2UtOWEzMi1jMTBjZTgzZDhmNjciLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI1YTMyMmNhNi1hOWI4LTQ1ZWEtYTJiMi00MWQ4MjlhODc4YmIifQ", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 200, + "response": "{\"recordingState\":\"active\"}", + "responseHeaders": { + "content-length": "27", + "content-type": "application/json; charset=utf-8", + "date": "Tue, 02 Nov 2021 19:43:02 GMT", + "x-azure-ref": "0xpSBYQAAAABuN293uG6SQIVpM+huSXp9V1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "855afe55-b989-40c0-a857-8f04d80c333c", + "x-ms-client-request-id": "526aadbf-ef9f-48c7-a7b8-715c58df314b" + } + }, + { + "method": "DELETE", + "url": "https://endpoint/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiJjNTFmMTMwMC1jODZmLTQ2M2UtOWEzMi1jMTBjZTgzZDhmNjciLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI1YTMyMmNhNi1hOWI4LTQ1ZWEtYTJiMi00MWQ4MjlhODc4YmIifQ", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 19:43:02 GMT", + "x-azure-ref": "0xpSBYQAAAABCPYHGS6EBRKM7S63CjSRUV1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "4d6727c9-6ba5-4aa9-a0c1-0a067a5de8ee", + "x-ms-client-request-id": "b2655eab-3973-489e-877a-1e35ccd3e087" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/callConnections/c51f1300-9c7f-47f3-a9ad-fe7a135c7abf/:hangup", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 19:43:02 GMT", + "x-azure-ref": "0x5SBYQAAAADgbTCrL5ELQ6njaSsP0o2OV1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "b20560e4-8a8f-404c-bb4d-9bd8acff1bba", + "x-ms-client-request-id": "2fc5e740-376d-4274-9678-e2833c4f61db" + } + }, + { + "method": "POST", + "url": "https://endpoint/calling/callConnections/c51f1300-1520-4845-bd29-f6002ad7fb0b/:hangup", + "query": { + "api-version": "2021-11-15-preview" + }, + "requestBody": null, + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Tue, 02 Nov 2021 19:43:02 GMT", + "x-azure-ref": "0x5SBYQAAAAALIVyemai1TaBfsms1+RPnV1NURURHRTA4MTgAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "x-cache": "CONFIG_NOCACHE", + "x-microsoft-skype-chain-id": "52396fcf-d229-48b8-a119-e9fc87ec2211", + "x-ms-client-request-id": "921f0a4f-c07f-458a-aab7-9350516f8858" + } + } + ], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "89971a0666fe081e988de4ce59cc6b62" +} \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/node/call_connection_live_test_call_automation_operations/recording_run_create_play_cancel_hangup_scenario.js b/sdk/communication/communication-calling-server/recordings/node/call_connection_live_test_call_automation_operations/recording_run_create_play_cancel_hangup_scenario.js new file mode 100644 index 000000000000..4fb030178255 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/call_connection_live_test_call_automation_operations/recording_run_create_play_cancel_hangup_scenario.js @@ -0,0 +1,111 @@ +let nock = require('nock'); + +module.exports.hash = "91ae5cf5c1a1f9f577c79320d44390bd"; + +module.exports.testInfo = {"uniqueName":{"audioFileId":"audioFileId163592632598100800","operationContext":"operationContext163592632598105415"},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/identities') + .query(true) + .reply(201, {"identity":{"id":"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_0000000d-84b0-5ac4-28c5-593a0d000f09"}}, [ + 'Content-Length', + '101', + 'Content-Type', + 'application/json; charset=utf-8', + 'Request-Context', + 'appId=', + 'MS-CV', + 'ej6CNrmzPUupKpV2nc/NXA.0', + 'Strict-Transport-Security', + 'max-age=2592000', + 'x-ms-client-request-id', + '70fc0088-75e7-44b9-9781-83b5076e88f8', + 'api-supported-versions', + '2020-07-20-preview2, 2021-02-22-preview1, 2021-03-07, 2021-03-31-preview1, 2021-10-31-preview', + 'X-Processing-Time', + '41ms', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0NEGCYQAAAABEpRS7JoBRSrEBAtOFuvN2V1NURURHRTA4MTYAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Wed, 03 Nov 2021 07:58:44 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/callConnections', {"alternateCallerId":{"value":"+18445764430"},"targets":[{"phoneNumber":{"value":"+15551234567"}}],"source":{"communicationUser":{"id":"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_0000000d-84b0-5ac4-28c5-593a0d000f09"}},"callbackUri":"https://endpoint/callback","requestedMediaTypes":["audio"],"requestedCallEvents":["participantsUpdated","toneReceived"]}) + .query(true) + .reply(201, {"callConnectionId":"d41f1300-c843-49e0-a241-1238b631c7d1"}, [ + 'Content-Length', + '59', + 'Content-Type', + 'application/json; charset=utf-8', + 'x-ms-client-request-id', + '6b93da44-ed9f-4a55-b3f1-cac6f5f4185b', + 'X-Microsoft-Skype-Chain-ID', + '85296700-e830-4253-91fa-0c871b120d79', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0NUGCYQAAAABeChp0FV+vRJd5ayqyAArcV1NURURHRTA4MjAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Wed, 03 Nov 2021 07:58:45 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/callConnections/d41f1300-c843-49e0-a241-1238b631c7d1/:playAudio', {"audioFileUri":"https://endpoint/audio/sample-message.wav","loop":true,"operationContext":"operationContext163592632598105415","audioFileId":"audioFileId163592632598100800","callbackUri":"https://endpoint/callback"}) + .query(true) + .reply(202, {"operationId":"3bd09c8c-7eef-40d4-812a-4043ebf1725c","status":"running","operationContext":"operationContext163592632598105415"}, [ + 'Content-Length', + '129', + 'Content-Type', + 'application/json; charset=utf-8', + 'X-Microsoft-Skype-Chain-ID', + 'dd643d2e-636c-4cba-94e4-e1523ef58c03', + 'x-ms-client-request-id', + '368643a3-1dd9-4fab-abcd-9287a4beaf31', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0QEGCYQAAAABxyyKPD1y3QbhPqjHTjf0TV1NURURHRTA4MjAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Wed, 03 Nov 2021 07:58:56 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/callConnections/d41f1300-c843-49e0-a241-1238b631c7d1/:cancelAllMediaOperations') + .query(true) + .reply(200, {"operationId":"aa43fa76-892b-481d-b88f-d630a952010c","status":"completed"}, [ + 'Content-Length', + '75', + 'Content-Type', + 'application/json; charset=utf-8', + 'X-Microsoft-Skype-Chain-ID', + 'a0fae5dc-445d-4fc6-8b20-78792dc1df18', + 'x-ms-client-request-id', + '508201e5-82ac-4735-bfec-163a69297ceb', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0QUGCYQAAAAB6ZaggdStwTIadZAI8/nKKV1NURURHRTA4MjAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Wed, 03 Nov 2021 07:58:56 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/callConnections/d41f1300-c843-49e0-a241-1238b631c7d1/:hangup') + .query(true) + .reply(202, "", [ + 'X-Microsoft-Skype-Chain-ID', + '2de7bc3d-c8db-4e45-8650-911a80d82ec7', + 'x-ms-client-request-id', + '91f520cc-6dff-44bb-acb6-efa74f51564b', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0S0GCYQAAAACcfEPpH8LIQ67GWHIRgq5YV1NURURHRTA4MjAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Wed, 03 Nov 2021 07:59:07 GMT', + 'Content-Length', + '0' +]); diff --git a/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_delete.js b/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_delete.js new file mode 100644 index 000000000000..ebd767717c33 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_delete.js @@ -0,0 +1,18 @@ +let nock = require('nock'); + +module.exports.hash = "2edca15d57c1511a41d4cbd310f4422b"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .delete('/v1/objects/0-wus-d6-fdf8ff0fdcd668bca8c52c0b1ee79b05') + .reply(200, "", [ + 'Content-Length', + '0', + 'Server', + 'Microsoft-HTTPAPI/2.0', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'Date', + 'Tue, 02 Nov 2021 17:43:52 GMT' +]); diff --git a/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_invalid_file_delete.js b/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_invalid_file_delete.js new file mode 100644 index 000000000000..ba24187cda73 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_invalid_file_delete.js @@ -0,0 +1,18 @@ +let nock = require('nock'); + +module.exports.hash = "0d9469b3f72006adfc5ffce15953963a"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .get('/v1/objects/0-wus-d4-ca4017a32f8514aa9f054f0917270000') + .reply(404, "", [ + 'Content-Length', + '0', + 'Server', + 'Microsoft-HTTPAPI/2.0', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'Date', + 'Tue, 02 Nov 2021 17:46:09 GMT' +]); diff --git a/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_unauthorized_delete.js b/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_unauthorized_delete.js new file mode 100644 index 000000000000..1305650d372d --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/delete_live_tests/recording_unauthorized_delete.js @@ -0,0 +1,18 @@ +let nock = require('nock'); + +module.exports.hash = "44aeeb9e1bce10c53420368854607266"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .delete('/v1/objects/0-wus-d6-fdf8ff0fdcd668bca8c52c0b1ee79b05') + .reply(401, "", [ + 'Content-Length', + '0', + 'Server', + 'Microsoft-HTTPAPI/2.0', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'Date', + 'Tue, 02 Nov 2021 17:46:09 GMT' +]); diff --git a/sdk/communication/communication-calling-server/recordings/node/download_content/recording_download.js b/sdk/communication/communication-calling-server/recordings/node/download_content/recording_download.js new file mode 100644 index 000000000000..ac69e364dacb --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/download_content/recording_download.js @@ -0,0 +1,24 @@ +let nock = require('nock'); + +module.exports.hash = "64c7ead96415eeaf2caea2f422e13ea4"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .get('/v1/objects/0-eus-d15-af5689148b0afa252a57a0121b744dcd/content/acsmetadata') + .reply(200, {"chunkDocumentId":"0-eus-d15-af5689148b0afa252a57a0121b744dcd"}, [ + 'Cache-Control', + 'no-cache, max-age=0, s-maxage=0, private', + 'Content-Length', + '64', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-63/64', + 'Server', + 'Microsoft-HTTPAPI/2.0', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'Date', + 'Tue, 12 Oct 2021 00:00:36 GMT' +]); \ No newline at end of file diff --git a/sdk/communication/communication-calling-server/recordings/node/download_content/recording_download_with_redirection.js b/sdk/communication/communication-calling-server/recordings/node/download_content/recording_download_with_redirection.js new file mode 100644 index 000000000000..adc2ca04b05c --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/download_content/recording_download_with_redirection.js @@ -0,0 +1,39 @@ +let nock = require('nock'); + +module.exports.hash = "a65e4119b09572bfeb3690a48d180edd"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .get('/v1/objects/0-sa-d4-a29f0c0212c0a2a634ab078245184de8/content/acsmetadata') + .reply(302, "", [ + 'Content-Length', + '0', + 'Location', + 'https://endpoint-sa/v1/objects/0-sa-d4-a29f0c0212c0a2a634ab078245184de8/content/acsmetadata', + 'Server', + 'Microsoft-HTTPAPI/2.0', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'Date', + 'Tue, 12 Oct 2021 17:25:35 GMT' +]); + +nock('https://endpoint-sa', {"encodedQueryParams":true}) + .get('/v1/objects/0-sa-d4-a29f0c0212c0a2a634ab078245184de8/content/acsmetadata') + .reply(200, {"chunkDocumentId":"0-sa-d4-a29f0c0212c0a2a634ab078245184de8"}, [ + 'Cache-Control', + 'no-cache, max-age=0, s-maxage=0, private', + 'Content-Length', + '62', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-61/62', + 'Server', + 'Microsoft-HTTPAPI/2.0', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'Date', + 'Tue, 12 Oct 2021 17:25:36 GMT' +]); diff --git a/sdk/communication/communication-calling-server/recordings/node/download_content/recording_unauthorized_download.js b/sdk/communication/communication-calling-server/recordings/node/download_content/recording_unauthorized_download.js new file mode 100644 index 000000000000..1075755740d8 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/download_content/recording_unauthorized_download.js @@ -0,0 +1,18 @@ +let nock = require('nock'); + +module.exports.hash = "e7c5a3c4d603c821ad2bc3db15664eb9"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .get('/v1/objects/0-eus-d15-af5689148b0afa252a57a0121b744dcd/content/acsmetadata') + .reply(401, "", [ + 'Content-Length', + '0', + 'Server', + 'Microsoft-HTTPAPI/2.0', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'Date', + 'Tue, 12 Oct 2021 16:42:40 GMT' +]); diff --git a/sdk/communication/communication-calling-server/recordings/node/server_call_live_test_recording_operations/recording_run_all_client_recording_operations.js b/sdk/communication/communication-calling-server/recordings/node/server_call_live_test_recording_operations/recording_run_all_client_recording_operations.js new file mode 100644 index 000000000000..ec983620ea09 --- /dev/null +++ b/sdk/communication/communication-calling-server/recordings/node/server_call_live_test_recording_operations/recording_run_all_client_recording_operations.js @@ -0,0 +1,215 @@ +let nock = require('nock'); + +module.exports.hash = "11ac49147386d3fc94db14f3b0ab509f"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling:join', {"callLocator":{"groupCallId":"31fccfc0-d804-5e92-9d9e-900b7b3eb6cc","kind":"groupCallLocator"},"source":{"communicationUser":{"id":"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_6f8c191d-f701-58b7-a744-35bac2a8f074"}},"callbackUri":"https://endpoint/callback","requestedMediaTypes":["audio"],"requestedCallEvents":["participantsUpdated"]}) + .query(true) + .reply(202, {"callConnectionId":"18201300-1d89-4624-af66-1d9ae49d41ed"}, [ + 'Content-Length', + '59', + 'Content-Type', + 'application/json; charset=utf-8', + 'x-ms-client-request-id', + '8d880e17-5cb4-45e2-836a-32b0203148d6', + 'X-Microsoft-Skype-Chain-ID', + '82457443-f4e6-4368-9a45-e3eee72ea886', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0X5SBYQAAAADg09vsqEupQrlQqHKWEslSV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:20 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling:join', {"callLocator":{"groupCallId":"31fccfc0-d804-5e92-9d9e-900b7b3eb6cc","kind":"groupCallLocator"},"source":{"communicationUser":{"id":"8:acs:016a7064-0581-40b9-be73-6dde64d69d72_ff23b678-5b97-564d-b6c4-6bb53068c498"}},"callbackUri":"https://endpoint/callback","requestedMediaTypes":["audio"],"requestedCallEvents":["participantsUpdated"]}) + .query(true) + .reply(202, {"callConnectionId":"18201300-b646-49dd-911a-70303cc6df27"}, [ + 'Content-Length', + '59', + 'Content-Type', + 'application/json; charset=utf-8', + 'x-ms-client-request-id', + '42a5e342-2559-4049-ada5-006773fdeca3', + 'X-Microsoft-Skype-Chain-ID', + 'a6905978-1ce6-41bb-a468-e249b3e7ca3c', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0YZSBYQAAAABDtHpEOQylTbuPq08cVhGJV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:21 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/recordings', {"callLocator":{"groupCallId":"31fccfc0-d804-5e92-9d9e-900b7b3eb6cc","kind":"groupCallLocator"},"recordingStateCallbackUri":"https://endpoint/callback"}) + .query(true) + .reply(200, {"recordingId":"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiIxODIwMTMwMC0yMTdlLTRmYTAtOWYzMC01MjFlYWQxZGZkNjEiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiJjZDcxM2Q1YS05ZDcxLTQ5NDUtYjkwYS03OGJlYTY1MTBhNDQifQ"}, [ + 'Content-Length', + '180', + 'Content-Type', + 'application/json; charset=utf-8', + 'x-ms-client-request-id', + '33d12f20-3e31-47a7-8b0f-573237971133', + 'X-Microsoft-Skype-Chain-ID', + '612a0231-72f9-4a33-ab75-d343c8596736', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0YpSBYQAAAADKcR/ZsivLTqND8TwV64s7V1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:26 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .get('/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiIxODIwMTMwMC0yMTdlLTRmYTAtOWYzMC01MjFlYWQxZGZkNjEiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiJjZDcxM2Q1YS05ZDcxLTQ5NDUtYjkwYS03OGJlYTY1MTBhNDQifQ') + .query(true) + .reply(200, {"recordingState":"active"}, [ + 'Content-Length', + '27', + 'Content-Type', + 'application/json; charset=utf-8', + 'X-Microsoft-Skype-Chain-ID', + '04ea09da-f574-46fd-b1c8-fd8969f40ba9', + 'x-ms-client-request-id', + '79307aa7-0f59-4aa3-afd7-d35ca5094c2e', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0cJSBYQAAAAD2+h4wTQggQpPnN5G1q8rlV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:36 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiIxODIwMTMwMC0yMTdlLTRmYTAtOWYzMC01MjFlYWQxZGZkNjEiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiJjZDcxM2Q1YS05ZDcxLTQ5NDUtYjkwYS03OGJlYTY1MTBhNDQifQ/:pause') + .query(true) + .reply(200, "", [ + 'X-Microsoft-Skype-Chain-ID', + '8a51e4bd-ad06-48e5-818a-125e4877ea27', + 'x-ms-client-request-id', + 'ae80d139-d7dd-4ef7-88fb-446a2ebd8d21', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0cZSBYQAAAAAOJbNz/cULTLNuI2N/5qdiV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:36 GMT', + 'Content-Length', + '0' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .get('/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiIxODIwMTMwMC0yMTdlLTRmYTAtOWYzMC01MjFlYWQxZGZkNjEiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiJjZDcxM2Q1YS05ZDcxLTQ5NDUtYjkwYS03OGJlYTY1MTBhNDQifQ') + .query(true) + .reply(200, {"recordingState":"inactive"}, [ + 'Content-Length', + '29', + 'Content-Type', + 'application/json; charset=utf-8', + 'X-Microsoft-Skype-Chain-ID', + '3c73e3dc-2074-4d44-abf4-eae49675a31f', + 'x-ms-client-request-id', + 'a40c513b-5f62-4d39-81a0-ef8721726bfb', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0e5SBYQAAAAC+8xDF0pZaTLcT4hX/ofYOV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:47 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiIxODIwMTMwMC0yMTdlLTRmYTAtOWYzMC01MjFlYWQxZGZkNjEiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiJjZDcxM2Q1YS05ZDcxLTQ5NDUtYjkwYS03OGJlYTY1MTBhNDQifQ/:resume') + .query(true) + .reply(200, "", [ + 'X-Microsoft-Skype-Chain-ID', + 'b206a1d8-558c-4a8e-bfca-46c68b1e59df', + 'x-ms-client-request-id', + 'df4eb977-3821-4813-9120-78f3ed0b6151', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0e5SBYQAAAAArDV9XJpgeQ6ApYl62sstiV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:47 GMT', + 'Content-Length', + '0' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .get('/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiIxODIwMTMwMC0yMTdlLTRmYTAtOWYzMC01MjFlYWQxZGZkNjEiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiJjZDcxM2Q1YS05ZDcxLTQ5NDUtYjkwYS03OGJlYTY1MTBhNDQifQ') + .query(true) + .reply(200, {"recordingState":"active"}, [ + 'Content-Length', + '27', + 'Content-Type', + 'application/json; charset=utf-8', + 'X-Microsoft-Skype-Chain-ID', + '95029a1c-bffc-4247-8a5d-5e62ee954d97', + 'x-ms-client-request-id', + '3bc2c036-29e6-408d-9424-27e77e9bbe4f', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0hZSBYQAAAAAOKAxpNrkMSIDeECT4rwwjV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:57 GMT' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .delete('/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiIxODIwMTMwMC0yMTdlLTRmYTAtOWYzMC01MjFlYWQxZGZkNjEiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiJjZDcxM2Q1YS05ZDcxLTQ5NDUtYjkwYS03OGJlYTY1MTBhNDQifQ') + .query(true) + .reply(200, "", [ + 'X-Microsoft-Skype-Chain-ID', + 'ac6efd75-32cd-45a1-b1ce-00ee529f714a', + 'x-ms-client-request-id', + '89455cf2-255d-4dfc-b7df-9d4b327f7b44', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0hZSBYQAAAAA0x1cYZzPYQJ0QLZamvhdVV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:57 GMT', + 'Content-Length', + '0' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/callConnections/18201300-1d89-4624-af66-1d9ae49d41ed/:hangup') + .query(true) + .reply(202, "", [ + 'X-Microsoft-Skype-Chain-ID', + '31306d71-62a9-48c3-893a-3fdcd7d0e7dc', + 'x-ms-client-request-id', + '1e2f6ea0-e05b-4fe3-b39e-b0de4ea29d6c', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0hpSBYQAAAADFC3/yN4iVT5JecI4EyBVRV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:57 GMT', + 'Content-Length', + '0' +]); + +nock('https://endpoint', {"encodedQueryParams":true}) + .post('/calling/callConnections/18201300-b646-49dd-911a-70303cc6df27/:hangup') + .query(true) + .reply(202, "", [ + 'X-Microsoft-Skype-Chain-ID', + '465dcafc-0832-4baa-a080-7d52e1933617', + 'x-ms-client-request-id', + 'd850299e-7e51-4ffa-8da0-c3f1f4c279e1', + 'X-Cache', + 'CONFIG_NOCACHE', + 'X-Azure-Ref', + '0hpSBYQAAAABnEtJER0Y+Q7WPei0UMNNMV1NURURHRTA4MDkAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx', + 'Date', + 'Tue, 02 Nov 2021 19:41:57 GMT', + 'Content-Length', + '0' +]); diff --git a/sdk/communication/communication-calling-server/review/communication-calling-server.api.md b/sdk/communication/communication-calling-server/review/communication-calling-server.api.md new file mode 100644 index 000000000000..653e31793db8 --- /dev/null +++ b/sdk/communication/communication-calling-server/review/communication-calling-server.api.md @@ -0,0 +1,346 @@ +## API Report File for "@azure/communication-calling-server" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { AbortSignalLike } from '@azure/abort-controller'; +import { CommunicationIdentifier } from '@azure/communication-common'; +import * as coreHttp from '@azure/core-http'; +import { HttpResponse } from '@azure/core-http'; +import { OperationOptions } from '@azure/core-http'; +import { OperationParameter } from '@azure/core-http'; +import { PhoneNumberIdentifier } from '@azure/communication-common'; +import { PipelineOptions } from '@azure/core-http'; +import { RestResponse } from '@azure/core-http'; +import { TokenCredential } from '@azure/core-auth'; +import { TransferProgressEvent } from '@azure/core-http'; + +// @public +export interface AddParticipantOptions extends OperationOptions { + alternateCallerId?: string; + operationContext?: string; +} + +// @public +export interface AddParticipantResult { + participantId?: string; +} + +// @public +export interface AddParticipantResultEvent { + operationContext?: string; + resultInfo?: CallingOperationResultDetails; + status: CallingOperationStatus; +} + +// @public +export interface CallConnection { + addParticipant(participant: CommunicationIdentifier, options?: AddParticipantOptions): Promise; + cancelAllMediaOperations(options?: CancelAllMediaOperationsOptions): Promise; + cancelParticipantMediaOperation(participant: CommunicationIdentifier, mediaOperationId: string, options?: CancelMediaOperationOptions): Promise; + getCallConnectionId(): string; + hangUp(options?: HangUpOptions): Promise; + playAudio(audioFileUri: string, options: PlayAudioOptions): Promise; + playAudioToParticipant(participant: CommunicationIdentifier, audioFileUri: string, options: PlayAudioOptions): Promise; + removeParticipant(participant: CommunicationIdentifier, options?: RemoveParticipantOptions): Promise; + transferCall(targetParticipant: CommunicationIdentifier, userToUserInformation: string, options?: TransferCallOptions): Promise; +} + +// @public +export type CallConnectionsAddParticipantResponse = AddParticipantResult & { + _response: coreHttp.HttpResponse & { + bodyAsText: string; + parsedBody: AddParticipantResult; + }; +}; + +// @public +export type CallConnectionsPlayAudioResponse = PlayAudioResult & { + _response: coreHttp.HttpResponse & { + bodyAsText: string; + parsedBody: PlayAudioResult; + }; +}; + +// @public +export type CallConnectionState = string; + +// @public +export interface CallConnectionStateChangedEvent { + callConnectionId?: string; + callConnectionState: CallConnectionState; + callLocator?: CallLocatorModel; +} + +// @public +export type CallingEventSubscriptionType = string; + +// @public +export interface CallingOperationResultDetails { + code: number; + message?: string; + subcode: number; +} + +// @public +export type CallingOperationStatus = string; + +// @public +export class CallingServerClient { + constructor(connectionString: string, options?: CallingServerClientOptions); + constructor(endpoint: string, credential: TokenCredential, options?: CallingServerClientOptions); + addParticipant(callLocator: CallLocator, participant: CommunicationIdentifier, callbackUri: string, options?: AddParticipantOptions): Promise; + cancelMediaOperation(callLocator: CallLocator, mediaOperationId: string, options?: CancelMediaOperationOptions): Promise; + cancelParticipantMediaOperation(callLocator: CallLocator, participant: CommunicationIdentifier, mediaOperationId: string, options?: CancelMediaOperationOptions): Promise; + createCallConnection(source: CommunicationIdentifier, targets: CommunicationIdentifier[], options: CreateCallConnectionOptions): Promise; + delete(deleteUri: string, options?: DeleteOptions): Promise; + download(uri: string, offset?: number, options?: DownloadOptions): Promise; + getCallConnection(callConnectionId: string): CallConnection; + getRecordingProperties(recordingId: string, options?: GetRecordingPropertiesOptions): Promise; + initializeContentDownloader(): ContentDownloader; + joinCall(callLocator: CallLocator, source: CommunicationIdentifier, options: JoinCallOptions): Promise; + pauseRecording(recordingId: string, options?: PauseRecordingOptions): Promise; + playAudio(callLocator: CallLocator, audioFileUri: string, options: PlayAudioOptions): Promise; + playAudioToParticipant(callLocator: CallLocator, participant: CommunicationIdentifier, audioFileUri: string, options: PlayAudioToParticipantOptions): Promise; + removeParticipant(callLocator: CallLocator, participant: CommunicationIdentifier, options?: RemoveParticipantOptions): Promise; + resumeRecording(recordingId: string, options?: ResumeRecordingOptions): Promise; + startRecording(callLocator: CallLocator, recordingStateCallbackUri: string, options?: StartRecordingOptions): Promise; + stopRecording(recordingId: string, options?: StopRecordingOptions): Promise; + } + +// @public +export interface CallingServerClientOptions extends PipelineOptions { +} + +// @public +export type CallingServerEventType = string; + +// @public +export enum CallingServerEventTypeValue { + AddParticipantResultEvent = "Microsoft.Communication.AddParticipantResult", + CallConnectionStateChangedEvent = "Microsoft.Communication.CallConnectionStateChanged", + CallRecordingStateChangedEvent = "Microsoft.Communication.CallRecordingStateChanged", + ParticipantsUpdatedEvent = "Microsoft.Communication.ParticipantsUpdated", + PlayAudioResultEvent = "Microsoft.Communication.PlayAudioResult", + ToneReceivedEvent = "Microsoft.Communication.ToneReceived" +} + +// @public +export type CallLocator = GroupCallLocator | ServerCallLocator; + +// @public +export type CallLocatorKind = GroupCallLocatorKind | ServerCallLocatorKind; + +// @public +export type CallLocatorKindModel = string; + +// @public +export interface CallLocatorModel { + groupCallId?: string; + kind?: CallLocatorKindModel; + serverCallId?: string; +} + +// @public +export type CallMediaType = string; + +// @public +export interface CallRecordingProperties { + recordingState: CallRecordingState; +} + +// @public +export type CallRecordingState = string; + +// @public +export type CancelAllMediaOperationsOptions = OperationOptions; + +// @public +export type CancelMediaOperationOptions = OperationOptions; + +// @public +export interface ContentDownloader { + downloadContent(contentUri: string, options: DownloadContentOptions): Promise; +} + +// @public +export interface ContentDownloadHeaders { + contentLength?: number; + contentRange?: string; + contentType?: string; + date?: Date; + errorCode?: string; +} + +// @public +export type ContentDownloadResponse = ContentDownloadHeaders & { + blobBody?: Promise; + readableStreamBody?: NodeJS.ReadableStream; + _response: HttpResponse & { + parsedHeaders: ContentDownloadHeaders; + }; +}; + +// @public +export interface CreateCallConnectionOptions extends OperationOptions { + alternateCallerId?: PhoneNumberIdentifier; + callbackUri: string; + requestedCallEvents: CallingEventSubscriptionType[]; + requestedMediaTypes: CallMediaType[]; + subject?: string; +} + +// @public +export type DeleteOptions = OperationOptions; + +// @public +export interface DownloadContentOptions extends DownloadOptions { + range?: string; +} + +// @public +export interface DownloadOptions extends OperationOptions { + abortSignal?: AbortSignalLike; + count?: number; + maxRetryRequests?: number; + onProgress?: (progress: TransferProgressEvent) => void; +} + +// @public +export const getLocatorKind: (locator: CallLocator) => CallLocatorKind; + +// @public +export type GetRecordingPropertiesOptions = OperationOptions; + +// @public +export interface GroupCallLocator { + groupCallId: string; +} + +// @public +export interface GroupCallLocatorKind extends GroupCallLocator { + kind: "groupCall"; +} + +// @public +export type HangUpOptions = OperationOptions; + +// @public +export const isGroupCallLocator: (locator: CallLocator) => locator is GroupCallLocator; + +// @public +export const isServerCallLocator: (locator: CallLocator) => locator is ServerCallLocator; + +// @public +export interface JoinCallOptions extends OperationOptions { + callbackUri: string; + requestedCallEvents?: CallingEventSubscriptionType[]; + requestedMediaTypes?: CallMediaType[]; + subject?: string; +} + +// @public +export type PauseRecordingOptions = OperationOptions; + +// @public +export interface PlayAudioOptions extends OperationOptions { + audioFileId: string; + callbackUri: string; + loop: boolean; + operationContext: string; +} + +// @public +export interface PlayAudioResult { + operationContext?: string; + operationId?: string; + resultInfo?: CallingOperationResultDetails; + status: CallingOperationStatus; +} + +// @public +export interface PlayAudioResultEvent { + operationContext?: string; + resultInfo?: CallingOperationResultDetails; + status: CallingOperationStatus; +} + +// @public +export type PlayAudioToParticipantOptions = PlayAudioOptions; + +// @public +export const range: OperationParameter; + +// @public +export type RecordingChannelType = string; + +// @public +export type RecordingContentType = string; + +// @public +export type RecordingFormatType = string; + +// @public +export type RemoveParticipantOptions = OperationOptions; + +// @public +export type ResumeRecordingOptions = OperationOptions; + +// @public +export interface ServerCallLocator { + serverCallId: string; +} + +// @public +export interface ServerCallLocatorKind extends ServerCallLocator { + kind: "serverCall"; +} + +// @public +export type ServerCallsAddParticipantResponse = AddParticipantResult & { + _response: coreHttp.HttpResponse & { + bodyAsText: string; + parsedBody: AddParticipantResult; + }; +}; + +// @public +export interface StartCallRecordingResult { + recordingId?: string; +} + +// @public +export interface StartRecordingOptions extends OperationOptions { + recordingChannelType?: RecordingChannelType; + recordingContentType?: RecordingContentType; + recordingFormatType?: RecordingFormatType; +} + +// @public +export type StopRecordingOptions = OperationOptions; + +export { TokenCredential } + +// @public +export interface ToneInfo { + sequenceId: number; + tone: ToneValue; +} + +// @public +export interface ToneReceivedEvent { + callConnectionId?: string; + toneInfo: ToneInfo; +} + +// @public +export type ToneValue = string; + +// @public +export type TransferCallOptions = OperationOptions; + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/sdk/communication/communication-calling-server/rollup.base.config.js b/sdk/communication/communication-calling-server/rollup.base.config.js new file mode 100644 index 000000000000..47822ca9a9da --- /dev/null +++ b/sdk/communication/communication-calling-server/rollup.base.config.js @@ -0,0 +1,139 @@ +import path from "path"; +import nodeResolve from "@rollup/plugin-node-resolve"; +import multiEntry from "@rollup/plugin-multi-entry"; +import cjs from "@rollup/plugin-commonjs"; +import json from "@rollup/plugin-json"; +import replace from "@rollup/plugin-replace"; +import { terser } from "rollup-plugin-terser"; +import sourcemaps from "rollup-plugin-sourcemaps"; +import viz from "rollup-plugin-visualizer"; +import shim from "rollup-plugin-shim"; +import { openTelemetryCommonJs } from "@azure/dev-tool/shared-config/rollup"; + +const pkg = require("./package.json"); +const depNames = Object.keys(pkg.dependencies); +const devDepNames = Object.keys(pkg.devDependencies); +const input = "dist-esm/src/index.js"; +const production = process.env.NODE_ENV === "production"; + +export function nodeConfig(test = false) { + const externalNodeBuiltins = ["events", "crypto", "stream"]; + const baseConfig = { + input: input, + external: depNames.concat(externalNodeBuiltins), + output: { file: "dist/index.js", format: "cjs", sourcemap: true }, + preserveSymlinks: false, + plugins: [ + sourcemaps(), + replace({ + delimiters: ["", ""], + values: { + // replace dynamic checks with if (true) since this is for node only. + // Allows rollup's dead code elimination to be more aggressive. + "if (isNode)": "if (true)", + "if (!isNode)": "if (false)" + } + }), + nodeResolve({ preferBuiltins: true }), + json(), + cjs() + ] + }; + + if (test) { + // Entry points - test files under the `test` folder(common for both browser and node), node specific test files + baseConfig.input = [ + "dist-esm/test/public/*.spec.js", + "dist-esm/test/internal/*.spec.js", + "dist-esm/test/public/node/*.spec.js", + "dist-esm/test/internal/node/*.spec.js" + ]; + baseConfig.plugins.unshift(multiEntry({ exports: false })); + + // different output file + baseConfig.output.file = "dist-test/index.node.js"; + + // mark assert as external + baseConfig.external.push("assert", ...devDepNames); + + // Disable tree-shaking of test code. In rollup-plugin-node-resolve@5.0.0, rollup started respecting + // the "sideEffects" field in package.json. Since our package.json sets "sideEffects=false", this also + // applies to test code, which causes all tests to be removed by tree-shaking. + baseConfig.treeshake = false; + } else if (production) { + baseConfig.plugins.push(terser()); + } + + return baseConfig; +} + +export function browserConfig(test = false) { + const baseConfig = { + input: input, + external: ["crypto"], + output: { + file: "dist-browser/azure-communication-calling-server.js", + format: "umd", + name: "Azure.Communication.CallingServer", + sourcemap: true, + globals: { "@azure/core-http": "Azure.Core.HTTP" } + }, + preserveSymlinks: false, + plugins: [ + sourcemaps(), + replace({ + delimiters: ["", ""], + values: { + // replace dynamic checks with if (false) since this is for + // browser only. Rollup's dead code elimination will remove + // any code guarded by if (isNode) { ... } + "if (isNode)": "if (false)", + "if (!isNode)": "if (true)" + } + }), + nodeResolve({ + mainFields: ["module", "browser"], + preferBuiltins: false + }), + cjs({ + namedExports: { + chai: ["assert"], + events: ["EventEmitter"], + ...openTelemetryCommonJs() + } + }), + viz({ filename: "dist-browser/browser-stats.html", sourcemap: false }) + ] + }; + + if (test) { + // Entry points - test files under the `test` folder(common for both browser and node), browser specific test files + baseConfig.input = [ + "dist-esm/test/public/*.spec.js", + "dist-esm/test/internal/*.spec.js", + "dist-esm/test/public/browser/*.spec.js", + "dist-esm/test/internal/browser/*.spec.js" + ]; + baseConfig.plugins.unshift(multiEntry({ exports: false })); + baseConfig.output.file = "dist-test/index.browser.js"; + + baseConfig.onwarn = (warning) => { + if ( + warning.code === "CIRCULAR_DEPENDENCY" && + warning.importer.indexOf(path.normalize("node_modules/chai/lib") === 0) + ) { + // Chai contains circular references, but they are not fatal and can be ignored. + return; + } + + console.error(`(!) ${warning.message}`); + }; + + // Disable tree-shaking of test code. In rollup-plugin-node-resolve@5.0.0, rollup started respecting + // the "sideEffects" field in package.json. Since our package.json sets "sideEffects=false", this also + // applies to test code, which causes all tests to be removed by tree-shaking. + baseConfig.treeshake = false; + } + + return baseConfig; +} diff --git a/sdk/communication/communication-calling-server/rollup.config.js b/sdk/communication/communication-calling-server/rollup.config.js new file mode 100644 index 000000000000..14652aa67ed8 --- /dev/null +++ b/sdk/communication/communication-calling-server/rollup.config.js @@ -0,0 +1,13 @@ +import * as base from "./rollup.base.config"; + +const inputs = []; + +if (!process.env.ONLY_BROWSER) { + inputs.push(base.nodeConfig()); +} + +if (!process.env.ONLY_NODE) { + inputs.push(base.browserConfig()); +} + +export default inputs; diff --git a/sdk/communication/communication-calling-server/rollup.test.config.js b/sdk/communication/communication-calling-server/rollup.test.config.js new file mode 100644 index 000000000000..925a4421a53e --- /dev/null +++ b/sdk/communication/communication-calling-server/rollup.test.config.js @@ -0,0 +1,3 @@ +import * as base from "./rollup.base.config"; + +export default [base.nodeConfig(true), base.browserConfig(true)]; diff --git a/sdk/communication/communication-calling-server/sample.env b/sdk/communication/communication-calling-server/sample.env new file mode 100644 index 000000000000..f3784c3cb72e --- /dev/null +++ b/sdk/communication/communication-calling-server/sample.env @@ -0,0 +1,4 @@ +# Used in most samples. Retrieve these values from a Communication Services resource +# in the Azure Portal. +COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING="endpoint=https://.communication.azure.net/;accessKey=" +COMMUNICATION_LIVETEST_STATIC_RESOURCE_IDENTIFIER="" diff --git a/sdk/communication/communication-calling-server/samples-dev/simpleSetUp.ts b/sdk/communication/communication-calling-server/samples-dev/simpleSetUp.ts new file mode 100644 index 000000000000..78d19081c397 --- /dev/null +++ b/sdk/communication/communication-calling-server/samples-dev/simpleSetUp.ts @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * @summary Issue a new Relay configuration + */ + +import { CallingServerClient } from "@azure/communication-calling-server"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +// You will need to set this environment variables or edit the following values +const connectionString = + process.env["COMMUNICATION_CONNECTION_STRING"] || ""; + +export async function main() { + console.log("\n== Get Relay configuration Sample ==\n"); + + // Create user + console.log("Creating User"); + + const client = new CallingServerClient(connectionString); + console.log("Getting relay configuration"); + + const config = await client.getCallConnection("test"); + console.log("RelayConfig", config); +} + +main().catch((error) => { + console.error("Encountered an error while issuing relay configuration: "); + console.error("Request: \n", error.request); + console.error("\nResponse: \n", error.response); + console.error(error); +}); diff --git a/sdk/communication/communication-calling-server/src/ContentDownloader.ts b/sdk/communication/communication-calling-server/src/ContentDownloader.ts new file mode 100644 index 000000000000..977b71664717 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/ContentDownloader.ts @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/// + +import { DownloadContentOptions } from "./models"; +import * as Parameters from "./parameters"; +import * as Mappers from "./generated/src/models/mappers"; +import * as ExtraMappers from "./mappers"; +import { CallingServerApiClientContext } from "./generated/src/callingServerApiClientContext"; +import { createSpan } from "./tracing"; +import { SpanStatusCode } from "@azure/core-tracing"; + +import { + operationOptionsToRequestOptionsBase, + OperationOptions, + OperationArguments, + Serializer, + OperationSpec +} from "@azure/core-http"; +import { ContentDownloadResponse } from "."; +import { CallingServerUtils } from "./utils/utils"; + +/** + * The ContentDownloader interface represents related APIs. + */ +export interface ContentDownloader { + /** + * Download recording's content. + * @param contentUri - The content Uri. + * @param options - The options parameters. + */ + downloadContent( + contentUri: string, + options: DownloadContentOptions + ): Promise; +} + +/** + * The ContentDownloader contains operations. + */ +export class ContentDownloaderImpl implements ContentDownloader { + private readonly client: CallingServerApiClientContext; + + constructor(client: CallingServerApiClientContext) { + this.client = client; + } + + /** + * Download recording's content. + * @param contentUri - The content Uri. + * @param options - The options parameters. + */ + public async downloadContent( + contentUri: string, + options: DownloadContentOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan( + "ContentDownloaderRestClient-downloadContent", + options + ); + + try { + return await this.download_content( + contentUri, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Download recording's content. + * @param contentUri - The content Uri. + * @param options - The options parameters. + */ + download_content( + contentUri: string, + options?: OperationOptions + ): Promise { + const operationArguments: OperationArguments = { + options: operationOptionsToRequestOptionsBase(options || {}) + }; + const stringToSign = CallingServerUtils.getStringToSign(this.client.endpoint, contentUri); + return this.client.sendOperationRequest( + operationArguments, + getDownloadContentOperationSpec(contentUri, stringToSign) + ) as Promise; + } +} + +// Operation Specifications +const serializer = new Serializer(Mappers, /* isXml */ false); + +function getDownloadContentOperationSpec(url: string, stringToSign: string): OperationSpec { + const stringToSignHeader = CallingServerUtils.getStringToSignHeader(stringToSign); + + const downloadContentOperationSpec: OperationSpec = { + path: "", + baseUrl: url, + httpMethod: "GET", + responses: { + 200: { + bodyMapper: { + type: { name: "Stream" }, + serializedName: "parsedResponse" + }, + headersMapper: ExtraMappers.ContentDownloadHeaders + }, + default: { + bodyMapper: Mappers.CommunicationErrorResponse + } + }, + requestBody: undefined, + queryParameters: [], + urlParameters: [], + headerParameters: [stringToSignHeader, Parameters.range], + serializer + }; + + return downloadContentOperationSpec; +} diff --git a/sdk/communication/communication-calling-server/src/Range.ts b/sdk/communication/communication-calling-server/src/Range.ts new file mode 100644 index 000000000000..a1ed74b18f18 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/Range.ts @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +// tslint:disable:max-line-length +/** + * Range for Download content Operations. + */ +export interface Range { + /** + * StartByte, larger than or equal 0. + */ + offset: number; + /** + * Optional. Count of bytes, larger than 0. + * If not provided, will return bytes from offset to the end. + */ + count?: number; +} + +/** + * Generate a range string. For example: + * + * "bytes=255-" or "bytes=0-511" + * + * @param iRange - + */ +export function rangeToString(iRange: Range): string { + if (iRange.offset < 0) { + throw new RangeError(`Range.offset cannot be smaller than 0.`); + } + if (iRange.count && iRange.count <= 0) { + throw new RangeError( + `Range.count must be larger than 0. Leave it undefined if you want a range from offset to the end.` + ); + } + return iRange.count + ? `bytes=${iRange.offset}-${iRange.offset + iRange.count - 1}` + : `bytes=${iRange.offset}-`; +} diff --git a/sdk/communication/communication-calling-server/src/RepeatableContentDownloadResponse.browser.ts b/sdk/communication/communication-calling-server/src/RepeatableContentDownloadResponse.browser.ts new file mode 100644 index 000000000000..dde0620450fc --- /dev/null +++ b/sdk/communication/communication-calling-server/src/RepeatableContentDownloadResponse.browser.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +// This file is used as a shim of "RepeatableContentDownloadResponse" for some browser bundlers +// when trying to bundle "RepeatableContentDownloadResponse" +// "RepeatableContentDownloadResponse" class is only available in Node.js runtime +export const RepeatableContentDownloadResponse = 1; diff --git a/sdk/communication/communication-calling-server/src/RepeatableContentDownloadResponse.ts b/sdk/communication/communication-calling-server/src/RepeatableContentDownloadResponse.ts new file mode 100644 index 000000000000..4126fab0fb2b --- /dev/null +++ b/sdk/communication/communication-calling-server/src/RepeatableContentDownloadResponse.ts @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import { HttpResponse, isNode } from "@azure/core-http"; +import { ContentDownloadHeaders, ContentDownloadResponse } from "."; +import { + ReadableStreamGetter, + RetriableReadableStream, + RetriableReadableStreamOptions +} from "./utils/RetriableReadableStream"; + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * RepeatableContentDownloadResponse implements ContentDownloadResponse interface, and in Node.js runtime it will + * automatically retry when internal read stream unexpected ends. (This kind of unexpected ends cannot + * trigger retries defined in pipeline retry policy.) + * + * The {@link readableStreamBody} stream will retry underlayer, you can just use it as a normal Node.js + * Readable stream. + */ +export class RepeatableContentDownloadResponse implements ContentDownloadResponse { + /** + * The number of bytes present in the + * response body. + * + * @readonly + */ + public get contentLength(): number | undefined { + return this.originalResponse.contentLength; + } + + /** + * Indicates the range of bytes returned if + * the client requested a subset of the content by setting the Range request + * header. + * + * @readonly + */ + public get contentRange(): string | undefined { + return this.originalResponse.contentRange; + } + + /** + * The content type specified for the content. + * The default content type is 'application/octet-stream' + * + * @readonly + */ + public get contentType(): string | undefined { + return this.originalResponse.contentType; + } + + /** + * A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + * + * @readonly + */ + public get date(): Date | undefined { + return this.originalResponse.date; + } + + /** + * The error code. + * + * @readonly + */ + public get errorCode(): string | undefined { + return this.originalResponse.errorCode; + } + + /** + * The response body as a browser Blob. + * Always undefined in node.js. + * + * @readonly + */ + public get contentAsBlob(): Promise | undefined { + return this.originalResponse.blobBody; + } + + /** + * The response body as a node.js Readable stream. + * Always undefined in the browser. + * + * It will automatically retry when internal read stream unexpected ends. + * + * @readonly + */ + public get readableStreamBody(): NodeJS.ReadableStream | undefined { + return isNode ? this.blobDownloadStream : undefined; + } + + /** + * The HTTP response. + */ + public get _response(): HttpResponse & { + parsedHeaders: ContentDownloadHeaders; + } { + return this.originalResponse._response; + } + + private originalResponse: ContentDownloadResponse; + private blobDownloadStream?: RetriableReadableStream; + + /** + * Creates an instance of ContentDownloadResponse. + * + * @param originalResponse - + * @param getter - + * @param offset - + * @param count - + * @param options - + */ + public constructor( + originalResponse: ContentDownloadResponse, + getter: ReadableStreamGetter, + offset: number, + count: number, + options: RetriableReadableStreamOptions = {} + ) { + this.originalResponse = originalResponse; + this.blobDownloadStream = new RetriableReadableStream( + this.originalResponse.readableStreamBody!, + getter, + offset, + count, + options + ); + } +} diff --git a/sdk/communication/communication-calling-server/src/callConnection.ts b/sdk/communication/communication-calling-server/src/callConnection.ts new file mode 100644 index 000000000000..2d6757ce500e --- /dev/null +++ b/sdk/communication/communication-calling-server/src/callConnection.ts @@ -0,0 +1,441 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/// + +import { CallConnections } from "./generated/src/operations"; +import { + PlayAudioRequest, + PlayAudioResult, + AddParticipantRequest, + CallConnectionsAddParticipantResponse, + RemoveParticipantRequest, + PlayAudioToParticipantRequest, + CancelParticipantMediaOperationRequest, + TransferCallRequest +} from "./generated/src/models"; +import { + HangUpOptions, + PlayAudioOptions, + CancelAllMediaOperationsOptions, + AddParticipantOptions, + RemoveParticipantOptions, + CancelMediaOperationOptions, + TransferCallOptions +} from "./models"; +import { + CommunicationIdentifier, + serializeCommunicationIdentifier +} from "@azure/communication-common"; + +import { createSpan } from "./tracing"; +import { operationOptionsToRequestOptionsBase } from "@azure/core-http"; +import { SpanStatusCode } from "@azure/core-tracing"; +import { extractOperationOptions } from "./extractOperationOptions"; + +/** + * A CallConnection interface represents call connection based APIs. + */ +export interface CallConnection { + /** + * Returns the call connection id. + */ + getCallConnectionId(): string; + + /** + * Disconnect the current caller in a group-call or end a p2p-call. + * + * @param options - Additional request options contains hangUp api options. + */ + hangUp(options?: HangUpOptions): Promise; + + /** + * Cancel all media operations in the call. + * + * @param options - Additional request options contains hangUp api options. + */ + cancelAllMediaOperations(options?: CancelAllMediaOperationsOptions): Promise; + + /** + * Play audio. + * + * @param audioFileUri - The id for the media in the AudioFileUri, using which we cache the media resource. + * @param options - Additional request options contains playAudio api options. + */ + playAudio(audioFileUri: string, options: PlayAudioOptions): Promise; + + /** + * Add participant to the call. + * + * @param participant - The identifier of the participant. + * @param options - Additional request options contains addParticipant api options. + */ + addParticipant( + participant: CommunicationIdentifier, + options?: AddParticipantOptions + ): Promise; + + /** + * Remove participant from the call. + * + * @param participant - The identifier of the participant. + * @param options - Additional request options contains removeParticipant api options. + */ + removeParticipant( + participant: CommunicationIdentifier, + options?: RemoveParticipantOptions + ): Promise; + + /** + * Play audio to a participant. + * + * @param participant - The identifier of the participant. + * @param audioFileUri - The id for the media in the AudioFileUri, using which we cache the media resource. + * @param options - Additional request options contains playAudioToParticipant api options. + */ + playAudioToParticipant( + participant: CommunicationIdentifier, + audioFileUri: string, + options: PlayAudioOptions + ): Promise; + + /** + * Cancel media operation of a participant. + * + * @param participant - The identifier of the participant. + * @param mediaOperationId - The operationId of the media operation to cancel. + * @param options - Additional request options contains cancelMediaOperation api options. + */ + cancelParticipantMediaOperation( + participant: CommunicationIdentifier, + mediaOperationId: string, + options?: CancelMediaOperationOptions + ): Promise; + + /** + * Transfer a call. + * + * @param targetParticipant - The identity of the target where call should be transfer to. + * @param userToUserInformation - The user to user information. + * @param options - Additional request options contains transferCall api options. + */ + transferCall( + targetParticipant: CommunicationIdentifier, + userToUserInformation: string, + options?: TransferCallOptions + ): Promise; +} + +/** + * The client to do call connection operations + */ +export class CallConnectionImpl implements CallConnection { + private readonly callConnectionId: string; + private readonly callConnectionRestClient: CallConnections; + + constructor(callConnectionId: string, callConnectionRestClient: CallConnections) { + this.callConnectionId = callConnectionId; + this.callConnectionRestClient = callConnectionRestClient; + } + + /** + * Returns the call connection id. + */ + public getCallConnectionId(): string { + return this.callConnectionId; + } + + /** + * Disconnect the current caller in a group-call or end a p2p-call. + * + * @param options - Additional request options contains hangUp api options. + */ + public async hangUp(options: HangUpOptions = {}): Promise { + const { span, updatedOptions } = createSpan("CallConnectionRestClient-HangUp", options); + + try { + await this.callConnectionRestClient.hangupCall( + this.callConnectionId, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Cancel all media operations in the call. + * + * @param options - Additional request options contains hangUp api options. + */ + public async cancelAllMediaOperations( + options: CancelAllMediaOperationsOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan( + "CallConnectionRestClient-CancelAllMediaOperations", + options + ); + + try { + await this.callConnectionRestClient.cancelAllMediaOperations( + this.callConnectionId, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Play audio. + * + * @param audioFileUri - The id for the media in the AudioFileUri, using which we cache the media resource. + * @param options - Additional request options contains playAudio api options. + */ + public async playAudio( + audioFileUri: string, + options: PlayAudioOptions + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan( + "CallConnectionRestClient-PlayAudio", + operationOptions + ); + + const request: PlayAudioRequest = { + audioFileUri: audioFileUri, + loop: restOptions.loop, + operationContext: restOptions.operationContext, + audioFileId: restOptions.audioFileId, + callbackUri: restOptions.callbackUri + }; + try { + const { ...result } = await this.callConnectionRestClient.playAudio( + this.callConnectionId, + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Add participant to the call. + * + * @param participant - The identifier of the participant. + * @param options - Additional request options contains addParticipant api options. + */ + public async addParticipant( + participant: CommunicationIdentifier, + options: AddParticipantOptions = {} + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan( + "CallConnectionRestClient-playAudio", + operationOptions + ); + const alternate_caller_id = + typeof restOptions?.alternateCallerId === "undefined" + ? restOptions?.alternateCallerId + : serializeCommunicationIdentifier({ phoneNumber: restOptions.alternateCallerId }) + .phoneNumber; + + const request: AddParticipantRequest = { + participant: serializeCommunicationIdentifier(participant), + alternateCallerId: alternate_caller_id, + operationContext: restOptions?.operationContext + }; + + try { + const { ...result } = await this.callConnectionRestClient.addParticipant( + this.callConnectionId, + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove participant from the call. + * + * @param participant - The identifier of the participant. + * @param options - Additional request options contains removeParticipant api options. + */ + public async removeParticipant( + participant: CommunicationIdentifier, + options: RemoveParticipantOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan( + "CallConnectionRestClient-removeParticipant", + options + ); + + const request: RemoveParticipantRequest = { + identifier: serializeCommunicationIdentifier(participant) + }; + + try { + await this.callConnectionRestClient.removeParticipant( + this.callConnectionId, + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Play audio to a participant. + * + * @param participant - The identifier of the participant. + * @param audioFileUri - The id for the media in the AudioFileUri, using which we cache the media resource. + * @param options - Additional request options contains playAudioToParticipant api options. + */ + public async playAudioToParticipant( + participant: CommunicationIdentifier, + audioFileUri: string, + options: PlayAudioOptions + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan( + "CallConnectionRestClient-playAudio", + operationOptions + ); + + const request: PlayAudioToParticipantRequest = { + identifier: serializeCommunicationIdentifier(participant), + audioFileUri: audioFileUri, + loop: restOptions.loop, + operationContext: restOptions.operationContext, + audioFileId: restOptions.audioFileId, + callbackUri: restOptions.callbackUri + }; + + try { + const { ...result } = await this.callConnectionRestClient.participantPlayAudio( + this.callConnectionId, + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Cancel media operation of a participant. + * + * @param participant - The identifier of the participant. + * @param mediaOperationId - The operationId of the media operation to cancel. + * @param options - Additional request options contains cancelMediaOperation api options. + */ + public async cancelParticipantMediaOperation( + participant: CommunicationIdentifier, + mediaOperationId: string, + options: CancelMediaOperationOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan( + "CallConnectionRestClient-cancelParticipantMediaOperation", + options + ); + + const request: CancelParticipantMediaOperationRequest = { + identifier: serializeCommunicationIdentifier(participant), + mediaOperationId: mediaOperationId + }; + + try { + await this.callConnectionRestClient.cancelParticipantMediaOperation( + this.callConnectionId, + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Transfer a call. + * + * @param targetParticipant - The identity of the target where call should be transfer to. + * @param userToUserInformation - The user to user information. + * @param options - Additional request options contains transferCall api options. + */ + public async transferCall( + targetParticipant: CommunicationIdentifier, + userToUserInformation: string, + options: TransferCallOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("CallConnectionRestClient-transferCall", options); + + const request: TransferCallRequest = { + targetParticipant: serializeCommunicationIdentifier(targetParticipant), + userToUserInformation: userToUserInformation + }; + + try { + await this.callConnectionRestClient.transfer( + this.callConnectionId, + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } +} diff --git a/sdk/communication/communication-calling-server/src/callLocatorModelSerializer.ts b/sdk/communication/communication-calling-server/src/callLocatorModelSerializer.ts new file mode 100644 index 000000000000..811e2deda91e --- /dev/null +++ b/sdk/communication/communication-calling-server/src/callLocatorModelSerializer.ts @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { GroupCallLocator, ServerCallLocator } from "."; +import { CallLocatorModel } from "./generated/src"; +import { CallLocator, CallLocatorKind, getLocatorKind } from "./models"; + +/** + * @hidden + * Identifies a callLocator in Azure Communication services. + */ +export interface SerializedCallLocator { + /** + * The group call. + */ + groupCall?: SerializedGroupCallLocator; + + /** + * The server call. + */ + serverCall?: SerializedServerCallLocator; +} + +/** + * @hidden + * GroupCallLocator. + */ +export interface SerializedGroupCallLocator { + /** + * The group call id. + */ + groupCallId: string; +} + +/** + * @hidden + * ServerCallLocator + */ +export interface SerializedServerCallLocator { + /** + * The server call id. + */ + serverCallId: string; +} + +const assertNotNullOrUndefined = < + T extends Record, + P extends keyof T, + Q extends keyof T[P] +>( + obj: T, + prop: Q +): Required[P]>[Q] => { + const subObjName = Object.keys(obj)[0]; + const subObj = (obj as any)[subObjName]; + if (prop in subObj) { + return subObj[prop]; + } + throw new Error(`Property ${prop} is required for identifier of type ${subObjName}.`); +}; + +const assertMaximumOneNestedModel = (locator: SerializedCallLocator): void => { + const { ...props } = locator; + const keys = Object.keys(props); + if (keys.length > 1) { + throw new Error(`Only one of the properties in ${JSON.stringify(keys)} should be present.`); + } +}; + +/** + * @hidden + * Translates a CallLocator to its serialized format for sending a request. + * @param locator - The CallLocator to be serialized. + */ +export const serializeCallLocator = (locator: CallLocator): CallLocatorModel => { + const locatorKind = getLocatorKind(locator); + switch (locatorKind.kind) { + case "groupCall": + return { + groupCallId: (locator as GroupCallLocator).groupCallId, + kind: locatorKind.kind + "Locator" + }; + case "serverCall": + return { + serverCallId: (locator as ServerCallLocator).serverCallId, + kind: locatorKind.kind + "Locator" + }; + default: + throw new Error(`Can't serialize an calllocator with kind ${(locatorKind as any).kind}`); + } +}; + +/** + * @hidden + * Translates the serialized format of a call locator to CallLocator. + * @param serializedCallLocator - The SerializedCallLocator to be deserialized. + */ +export const deserializeCallLocator = ( + serializedCallLocator: SerializedCallLocator +): CallLocatorKind => { + assertMaximumOneNestedModel(serializedCallLocator); + + const { groupCall, serverCall } = serializedCallLocator; + if (groupCall) { + return { + kind: "groupCall", + groupCallId: assertNotNullOrUndefined({ groupCall }, "groupCallId") + }; + } + if (serverCall) { + return { + kind: "serverCall", + serverCallId: assertNotNullOrUndefined({ serverCall }, "serverCallId") + }; + } + throw new Error( + `Can't deserialize an serializedCallLocator with ${serializedCallLocator as any}` + ); +}; diff --git a/sdk/communication/communication-calling-server/src/callingServerClient.ts b/sdk/communication/communication-calling-server/src/callingServerClient.ts new file mode 100644 index 000000000000..ad379425dcd4 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/callingServerClient.ts @@ -0,0 +1,884 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/// + +import { CallConnection, ContentDownloadResponse } from "."; +import { CallConnectionImpl } from "./callConnection"; +import { + CreateCallConnectionOptions, + DownloadOptions, + JoinCallOptions, + CallLocator, + PlayAudioOptions, + PlayAudioToParticipantOptions, + AddParticipantOptions, + RemoveParticipantOptions, + CancelMediaOperationOptions, + StartRecordingOptions, + PauseRecordingOptions, + ResumeRecordingOptions, + StopRecordingOptions, + GetRecordingPropertiesOptions, + DeleteOptions +} from "./models"; +import { CallConnections, ServerCalls } from "./generated/src/operations"; +import { + CreateCallRequest, + JoinCallRequest, + PlayAudioWithCallLocatorRequest, + PlayAudioResult, + PlayAudioToParticipantWithCallLocatorRequest, + ServerCallsAddParticipantResponse, + AddParticipantWithCallLocatorRequest, + RemoveParticipantWithCallLocatorRequest, + CancelMediaOperationWithCallLocatorRequest, + CancelParticipantMediaOperationWithCallLocatorRequest, + StartCallRecordingResult, + StartCallRecordingWithCallLocatorRequest, + CallRecordingProperties +} from "./generated/src/models"; +import * as Mappers from "./generated/src/models/mappers"; +import { TokenCredential } from "@azure/core-auth"; + +import { + parseClientArguments, + isKeyCredential, + createCommunicationAuthPolicy, + CommunicationIdentifier, + serializeCommunicationIdentifier +} from "@azure/communication-common"; +import { + isNode, + PipelineOptions, + InternalPipelineOptions, + createPipelineFromOptions, + operationOptionsToRequestOptionsBase, + RestResponse, + OperationArguments, + OperationSpec, + Serializer +} from "@azure/core-http"; +import { SpanStatusCode } from "@azure/core-tracing"; +import { CallingServerApiClient } from "./generated/src/callingServerApiClient"; +import { CallingServerApiClientContext } from "./generated/src/callingServerApiClientContext"; +import { SDK_VERSION } from "./constants"; +import { convertTracingToRequestOptionsBase, createSpan } from "./tracing"; +import { logger } from "./logger"; +import { ContentDownloader, ContentDownloaderImpl } from "./ContentDownloader"; +import { rangeToString } from "./Range"; +import { RepeatableContentDownloadResponse } from "./RepeatableContentDownloadResponse"; +import { extractOperationOptions } from "./extractOperationOptions"; +import { CallingServerUtils } from "./utils/utils"; +import { serializeCallLocator } from "./callLocatorModelSerializer"; + +/** + * Client options used to configure CallingServer Client API requests. + */ +export interface CallingServerClientOptions extends PipelineOptions {} + +/** + * Checks whether the type of a value is CallingServerClientOptions or not. + * + * @param options - The value being checked. + */ +const isCallingServerClientOptions = (options: any): options is CallingServerClientOptions => + !!options && !isKeyCredential(options); + +/** + * A CallingServerClient represents a Client to the Azure Communication CallingServer service. + */ +export class CallingServerClient { + private readonly callingServerServiceClient: CallingServerApiClient; + private readonly callConnectionRestClient: CallConnections; + private readonly serverCallRestClient: ServerCalls; + private readonly storageApiClient: CallingServerApiClientContext; + + /** + * Initializes a new instance of the CallingServerClient class. + * @param connectionString - Connection string to connect to an Azure Communication Service resource. + * Example: "endpoint=https://contoso.eastus.communications.azure.net/;accesskey=secret"; + * @param options - Optional. Options to configure the HTTP pipeline. + */ + constructor(connectionString: string, options?: CallingServerClientOptions); + + /** + * Initializes a new instance of the SmsClient class using a TokenCredential. + * @param endpoint - The endpoint of the service (ex: https://contoso.eastus.communications.azure.net). + * @param credential - TokenCredential that is used to authenticate requests to the service. + * @param options - Optional. Options to configure the HTTP pipeline. + */ + constructor(endpoint: string, credential: TokenCredential, options?: CallingServerClientOptions); + + constructor( + connectionStringOrUrl: string, + credentialOrOptions?: TokenCredential | CallingServerClientOptions, + maybeOptions: CallingServerClientOptions = {} + ) { + const { url, credential } = parseClientArguments(connectionStringOrUrl, credentialOrOptions); + const options = isCallingServerClientOptions(credentialOrOptions) + ? credentialOrOptions + : maybeOptions; + const libInfo = `azsdk-js-communication-calling-server/${SDK_VERSION}`; + + if (!options?.userAgentOptions) { + options.userAgentOptions = {}; + } + + if (options?.userAgentOptions?.userAgentPrefix) { + options.userAgentOptions.userAgentPrefix = `${options.userAgentOptions.userAgentPrefix} ${libInfo}`; + } else { + options.userAgentOptions.userAgentPrefix = libInfo; + } + + const internalPipelineOptions: InternalPipelineOptions = { + ...options, + ...{ + loggingOptions: { + logger: logger.info + } + } + }; + + const authPolicy = createCommunicationAuthPolicy(credential); + const pipeline = createPipelineFromOptions(internalPipelineOptions, authPolicy); + this.callingServerServiceClient = new CallingServerApiClient(url, pipeline); + this.callConnectionRestClient = this.callingServerServiceClient.callConnections; + this.serverCallRestClient = this.callingServerServiceClient.serverCalls; + this.storageApiClient = new CallingServerApiClientContext(url, pipeline); + } + + /** + * Initializes a new instance of CallConnection using a callConnectionId. + * @param callConnectionId - The CallConnection id for the CallConnection instance. (ex: endpoint=https://REDACTED.communication.azure.com/;accesskey=eyJhbG==). + */ + public getCallConnection(callConnectionId: string): CallConnection { + return new CallConnectionImpl(callConnectionId, this.callConnectionRestClient); + } + + /** + * Initializes a new instance of ContentDownloader. + */ + public initializeContentDownloader(): ContentDownloader { + return new ContentDownloaderImpl(this.storageApiClient); + } + + /** + * Create an outgoing call from source to target identities. + * @param source - The source identity. + * @param targets - The target identities. + * @param options - Additional request options contains createCallConnection api options. + */ + public async createCallConnection( + source: CommunicationIdentifier, + targets: CommunicationIdentifier[], + options: CreateCallConnectionOptions + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan( + "CallConnectionRestClient-CreateCallOptions", + operationOptions + ); + + const request: CreateCallRequest = { + source: serializeCommunicationIdentifier(source), + targets: targets.map((m) => serializeCommunicationIdentifier(m)), + callbackUri: restOptions.callbackUri, + requestedMediaTypes: restOptions.requestedMediaTypes, + requestedCallEvents: restOptions.requestedCallEvents, + alternateCallerId: + restOptions.alternateCallerId == null + ? undefined + : { value: restOptions.alternateCallerId.phoneNumber }, + subject: restOptions.subject + }; + + try { + const { ...result } = await this.callConnectionRestClient.createCall( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + + if (result.callConnectionId) { + return new CallConnectionImpl(result.callConnectionId, this.callConnectionRestClient); + } + throw "callConnectionId is missing in createCall result"; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Join the call using callLocator. + * + * @param callLocator - The callLocator contains call id. + * @param source - The source identity. + * @param options - Additional request options contains joinCall api options. + */ + public async joinCall( + callLocator: CallLocator, + source: CommunicationIdentifier, + options: JoinCallOptions + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan("ServerCallRestClient-JoinCall", operationOptions); + + const request: JoinCallRequest = { + callLocator: serializeCallLocator(callLocator), + source: serializeCommunicationIdentifier(source), + callbackUri: restOptions.callbackUri, + requestedMediaTypes: restOptions.requestedMediaTypes, + requestedCallEvents: restOptions.requestedCallEvents, + subject: undefined + }; + + try { + const { ...result } = await this.serverCallRestClient.joinCall( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + + if (result.callConnectionId) { + return new CallConnectionImpl(result.callConnectionId, this.callConnectionRestClient); + } else { + throw "callConnectionId is missing in joinCall result"; + } + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Play audio using callLocator. + * + * @param callLocator - The callLocator contains call id. + * @param audioFileUri - The id for the media in the AudioFileUri, using which we cache the media resource. + * @param options - Additional request options contains playAudio api options. + */ + public async playAudio( + callLocator: CallLocator, + audioFileUri: string, + options: PlayAudioOptions + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan("ServerCallRestClient-playAudio", operationOptions); + + const request: PlayAudioWithCallLocatorRequest = { + callLocator: callLocator, + audioFileUri: audioFileUri, + loop: restOptions.loop, + operationContext: restOptions.operationContext, + audioFileId: restOptions.audioFileId, + callbackUri: restOptions.callbackUri + }; + + try { + const { ...result } = await this.serverCallRestClient.playAudio( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Play audio to a participant using callLocator. + * + * @param callLocator - The callLocator contains call id. + * @param participant - The identifier of the participant. + * @param audioFileUri - The id for the media in the AudioFileUri, using which we cache the media resource. + * @param options - Additional request options contains playAudioToParticipant api options. + */ + public async playAudioToParticipant( + callLocator: CallLocator, + participant: CommunicationIdentifier, + audioFileUri: string, + options: PlayAudioToParticipantOptions + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan("ServerCallRestClient-playAudio", operationOptions); + + const request: PlayAudioToParticipantWithCallLocatorRequest = { + callLocator: callLocator, + identifier: serializeCommunicationIdentifier(participant), + audioFileUri: audioFileUri, + loop: restOptions.loop, + operationContext: restOptions.operationContext, + audioFileId: restOptions.audioFileId, + callbackUri: restOptions.callbackUri + }; + + try { + const { ...result } = await this.serverCallRestClient.participantPlayAudio( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Add participant to the call using call_locator. + * + * @param callLocator - The callLocator contains call id. + * @param participant - The identifier of the participant. + * @param callbackUri - The callback uri to receive the notification. + * @param options - Additional request options contains addParticipant api options. + */ + public async addParticipant( + callLocator: CallLocator, + participant: CommunicationIdentifier, + callbackUri: string, + options: AddParticipantOptions = {} + ): Promise { + const { operationOptions, restOptions } = extractOperationOptions(options); + const { span, updatedOptions } = createSpan("ServerCallRestClient-playAudio", operationOptions); + const alternate_caller_id = + typeof restOptions?.alternateCallerId === "undefined" + ? restOptions?.alternateCallerId + : serializeCommunicationIdentifier({ phoneNumber: restOptions.alternateCallerId }) + .phoneNumber; + + const request: AddParticipantWithCallLocatorRequest = { + callLocator: callLocator, + participant: serializeCommunicationIdentifier(participant), + alternateCallerId: alternate_caller_id, + operationContext: restOptions?.operationContext, + callbackUri: callbackUri + }; + + try { + const { ...result } = await this.serverCallRestClient.addParticipant( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove participant from the call using call_locator. + * + * @param callLocator - The callLocator contains call id. + * @param participant - The identifier of the participant. + * @param options - Additional request options contains removeParticipant api options. + */ + public async removeParticipant( + callLocator: CallLocator, + participant: CommunicationIdentifier, + options: RemoveParticipantOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-removeParticipant", options); + + const request: RemoveParticipantWithCallLocatorRequest = { + callLocator: callLocator, + identifier: serializeCommunicationIdentifier(participant) + }; + + try { + await this.serverCallRestClient.removeParticipant( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Cancel media operation in the call using call_locator. + * + * @param callLocator - The callLocator contains call id. + * @param mediaOperationId - The operationId of the media operation to cancel. + * @param options - Additional request options contains cancelMediaOperation api options. + */ + public async cancelMediaOperation( + callLocator: CallLocator, + mediaOperationId: string, + options: CancelMediaOperationOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan( + "ServerCallRestClient-cancelMediaOperation", + options + ); + + const request: CancelMediaOperationWithCallLocatorRequest = { + callLocator: callLocator, + mediaOperationId: mediaOperationId + }; + + try { + await this.serverCallRestClient.cancelMediaOperation( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Cancel media operation of a participant using call_locator. + * + * @param callLocator - The callLocator contains call id. + * @param participant - The identifier of the participant. + * @param mediaOperationId - The operationId of the media operation to cancel. + * @param options - Additional request options contains cancelMediaOperation api options. + */ + public async cancelParticipantMediaOperation( + callLocator: CallLocator, + participant: CommunicationIdentifier, + mediaOperationId: string, + options: CancelMediaOperationOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan( + "ServerCallRestClient-cancelParticipantMediaOperation", + options + ); + + const request: CancelParticipantMediaOperationWithCallLocatorRequest = { + callLocator: callLocator, + identifier: serializeCommunicationIdentifier(participant), + mediaOperationId: mediaOperationId + }; + + try { + await this.serverCallRestClient.cancelParticipantMediaOperation( + request, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Start recording operation using call locator. + * + * @param callLocator - The callLocator contains server call id. + * @param recordingStateCallbackUri - The call back uri for recording state. + * @param options - Additional request options contains StartRecording api options. + */ + public async startRecording( + callLocator: CallLocator, + recordingStateCallbackUri: string, + options: StartRecordingOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-StartRecording", options); + + if (typeof callLocator === "undefined" || !callLocator) { + throw new Error("callLocator is invalid."); + } + + if ( + typeof recordingStateCallbackUri === "undefined" || + !recordingStateCallbackUri || + !CallingServerUtils.isValidUrl(recordingStateCallbackUri) + ) { + throw new Error("recordingStateCallbackUri is invalid."); + } + + const startCallRecordingWithCallLocatorRequest: StartCallRecordingWithCallLocatorRequest = { + callLocator: serializeCallLocator(callLocator), + recordingStateCallbackUri: recordingStateCallbackUri, + ...updatedOptions + }; + + try { + const result = await this.serverCallRestClient.startRecording( + startCallRecordingWithCallLocatorRequest, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Pause recording operation using recording id. + * + * @param recordingId - The recording id of the ongoing recording. + * @param options - Additional request options contains PauseRecording api options. + */ + public async pauseRecording( + recordingId: string, + options: PauseRecordingOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-PauseRecording", options); + + if (typeof recordingId === "undefined" || !recordingId || !recordingId.trim()) { + throw new Error("recordingId is invalid."); + } + + try { + const result = await this.serverCallRestClient.pauseRecording( + recordingId, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Resume recording operation using recording id. + * + * @param recordingId - The recording id of the ongoing recording. + * @param options - Additional request options contains ResumeRecording api options. + */ + public async resumeRecording( + recordingId: string, + options: ResumeRecordingOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-ResumeRecording", options); + + if (typeof recordingId === "undefined" || !recordingId || !recordingId.trim()) { + throw new Error("recordingId is invalid."); + } + + try { + const result = await this.serverCallRestClient.resumeRecording( + recordingId, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Stop recording operation using recording id. + * + * @param recordingId - The recording id of the ongoing recording. + * @param options - Additional request options contains StopRecording api options. + */ + public async stopRecording( + recordingId: string, + options: StopRecordingOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-StopRecording", options); + if (typeof recordingId === "undefined" || !recordingId || !recordingId.trim()) { + throw new Error("recordingId is invalid."); + } + + try { + const result = await this.serverCallRestClient.stopRecording( + recordingId, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Get recording properties using recording id. + * + * @param recordingId - The recording id of the ongoing recording. + * @param options - Additional request options contains GetRecordingState api options. + */ + public async getRecordingProperties( + recordingId: string, + options: GetRecordingPropertiesOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-Recording", options); + + if (typeof recordingId === "undefined" || !recordingId || !recordingId.trim()) { + throw new Error("recordingId is invalid."); + } + + try { + const result = await this.serverCallRestClient.getRecordingProperties( + recordingId, + operationOptionsToRequestOptionsBase(updatedOptions) + ); + return result; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Downloads the content pointed to the uri passed as a parameter. + * + * * In Node.js, data returns in a Readable stream readableStreamBody + * * In browsers, data returns in a promise blobBody + * + * @param uri - Endpoint where the content exists. + * @param offset - From which position of the blob to download, greater than or equal to 0. + * @param count - How much data to be downloaded, greater than 0. Will download to the end when undefined + * @param options - Optional options to Download operation. + * + * + * Example usage (Node.js): + * + * ```js + * // Download and convert a blob to a string + * const downloadResponse = await callingServerClient.download(); + * const downloaded = await streamToBuffer(downloadResponse.readableStreamBody); + * console.log("Downloaded content:", downloaded.toString()); + * + * async function streamToBuffer(readableStream) { + * return new Promise((resolve, reject) => { + * const chunks = []; + * readableStream.on("data", (data) => { + * chunks.push(data instanceof Buffer ? data : Buffer.from(data)); + * }); + * readableStream.on("end", () => { + * resolve(Buffer.concat(chunks)); + * }); + * readableStream.on("error", reject); + * }); + * } + * ``` + * + * Example usage (browser): + * + * ```js + * // Download and convert a content blob to a string + * const downloadResponse = await callingServerClient.download(); + * const downloaded = await blobToString(await downloadResponse.blobBody); + * console.log( + * "Downloaded blob content", + * downloaded + * ); + * + * async function blobToString(blob: Blob): Promise { + * const fileReader = new FileReader(); + * return new Promise((resolve, reject) => { + * fileReader.onloadend = (ev: any) => { + * resolve(ev.target!.result); + * }; + * fileReader.onerror = reject; + * fileReader.readAsText(blob); + * }); + * } + * ``` + */ + public async download( + uri: string, + offset: number = 0, + options: DownloadOptions = {} + ): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-download", options); + const DEFAULT_MAX_DOWNLOAD_RETRY_REQUESTS = 3; + const contentDownloader = this.initializeContentDownloader(); + try { + const count = updatedOptions.count; + const res = await contentDownloader.downloadContent(uri, { + abortSignal: options.abortSignal, + requestOptions: { + onDownloadProgress: isNode ? undefined : options.onProgress // for Node.js, progress is reported by RetriableReadableStream + }, + range: offset === 0 && !count ? undefined : rangeToString({ offset, count }), + ...convertTracingToRequestOptionsBase(updatedOptions) + }); + + // Return browser response immediately + if (!isNode) { + return res; + } + + // We support retrying when download stream unexpected ends in Node.js runtime + if (options.maxRetryRequests === undefined || options.maxRetryRequests < 0) { + options.maxRetryRequests = DEFAULT_MAX_DOWNLOAD_RETRY_REQUESTS; + } + + if (res.contentLength === undefined) { + throw new RangeError(`File download response doesn't contain valid content length header`); + } + return new RepeatableContentDownloadResponse( + res, + async (start: number): Promise => { + // Debug purpose only + // console.log( + // `Read from internal stream, range: ${ + // updatedOptions.range + // }, options: ${JSON.stringify(updatedOptions)}` + // ); + + return ( + await contentDownloader.downloadContent(uri, { + abortSignal: options.abortSignal, + range: rangeToString({ + count: offset + res.contentLength! - start, + offset: start + }), + ...convertTracingToRequestOptionsBase(updatedOptions) + }) + ).readableStreamBody!; + }, + offset, + res.contentLength!, + { + maxRetryRequests: options.maxRetryRequests, + onProgress: options.onProgress + } + ); + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + + /** + * Deletes the content pointed to the uri passed as a parameter. + * + * * Returns a RestResponse indicating the result of the delete operation. + * + * @param deleteUri - Endpoint where the content exists. + * + * Example usage: + * + * ```js + * // Delete content + * const deleteUri = "https://deleteUri.com"; + * const deleteResponse = await callingServerClient.delete(deleteUri); + * + * ``` + */ + public async delete(deleteUri: string, options: DeleteOptions = {}): Promise { + const { span, updatedOptions } = createSpan("ServerCallRestClient-delete", options); + + const operationArguments: OperationArguments = { + options: operationOptionsToRequestOptionsBase(updatedOptions) + }; + + try { + const stringToSign = CallingServerUtils.getStringToSign( + this.storageApiClient.endpoint, + deleteUri + ); + return this.storageApiClient.sendOperationRequest( + operationArguments, + getDeleteOperationSpec(deleteUri, stringToSign) + ) as Promise; + } catch (e) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } +} + +function getDeleteOperationSpec(url: string, stringToSign: string): OperationSpec { + // Operation Specifications + const serializer = new Serializer(Mappers, /* isXml */ false); + const stringToSignHeader = CallingServerUtils.getStringToSignHeader(stringToSign); + const hostHeader = CallingServerUtils.getMsHostHeaders(stringToSign); + + const deleteOperationSpec: OperationSpec = { + path: "", + baseUrl: url, + httpMethod: "DELETE", + responses: { + 200: {}, + default: { + bodyMapper: Mappers.CommunicationErrorResponse + } + }, + requestBody: undefined, + queryParameters: [], + urlParameters: [], + headerParameters: [stringToSignHeader, hostHeader], + serializer + }; + + return deleteOperationSpec; +} diff --git a/sdk/communication/communication-calling-server/src/constants.ts b/sdk/communication/communication-calling-server/src/constants.ts new file mode 100644 index 000000000000..47dc16dd0f7c --- /dev/null +++ b/sdk/communication/communication-calling-server/src/constants.ts @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export const SDK_VERSION: string = "1.0.0-beta.1"; diff --git a/sdk/communication/communication-calling-server/src/extractOperationOptions.ts b/sdk/communication/communication-calling-server/src/extractOperationOptions.ts new file mode 100644 index 000000000000..87a31800ba00 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/extractOperationOptions.ts @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { OperationOptions } from "@azure/core-http"; + +export const extractOperationOptions = ( + obj: T +): { + operationOptions: OperationOptions; + restOptions: Pick>; +} => { + const { abortSignal, requestOptions, tracingOptions, ...restOptions } = obj; + + return { + operationOptions: { + abortSignal, + requestOptions, + tracingOptions + }, + restOptions + }; +}; diff --git a/sdk/communication/communication-calling-server/src/generated/src/callingServerApiClient.ts b/sdk/communication/communication-calling-server/src/generated/src/callingServerApiClient.ts new file mode 100644 index 000000000000..24ee49683594 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/callingServerApiClient.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +import { CallConnections, ServerCalls } from "./operations"; +import { CallingServerApiClientContext } from "./callingServerApiClientContext"; +import { CallingServerApiClientOptionalParams } from "./models"; + +export class CallingServerApiClient extends CallingServerApiClientContext { + /** + * Initializes a new instance of the CallingServerApiClient class. + * @param endpoint The endpoint of the Azure Communication resource. + * @param options The parameter options + */ + constructor( + endpoint: string, + options?: CallingServerApiClientOptionalParams + ) { + super(endpoint, options); + this.callConnections = new CallConnections(this); + this.serverCalls = new ServerCalls(this); + } + + callConnections: CallConnections; + serverCalls: ServerCalls; +} diff --git a/sdk/communication/communication-calling-server/src/generated/src/callingServerApiClientContext.ts b/sdk/communication/communication-calling-server/src/generated/src/callingServerApiClientContext.ts new file mode 100644 index 000000000000..2c3ab3d5e142 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/callingServerApiClientContext.ts @@ -0,0 +1,54 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +import * as coreHttp from "@azure/core-http"; +import { CallingServerApiClientOptionalParams } from "./models"; + +const packageName = "azure-communication-calling-server"; +const packageVersion = "1.0.0-beta.1"; + +export class CallingServerApiClientContext extends coreHttp.ServiceClient { + endpoint: string; + apiVersion: string; + + /** + * Initializes a new instance of the CallingServerApiClientContext class. + * @param endpoint The endpoint of the Azure Communication resource. + * @param options The parameter options + */ + constructor( + endpoint: string, + options?: CallingServerApiClientOptionalParams + ) { + if (endpoint === undefined) { + throw new Error("'endpoint' cannot be null"); + } + + // Initializing default values for options + if (!options) { + options = {}; + } + + if (!options.userAgent) { + const defaultUserAgent = coreHttp.getDefaultUserAgentValue(); + options.userAgent = `${packageName}/${packageVersion} ${defaultUserAgent}`; + } + + super(undefined, options); + + this.requestContentType = "application/json; charset=utf-8"; + + this.baseUri = options.endpoint || "{endpoint}"; + + // Parameter assignments + this.endpoint = endpoint; + + // Assigning values to Constant parameters + this.apiVersion = options.apiVersion || "2021-11-15-preview"; + } +} diff --git a/sdk/communication/communication-calling-server/src/generated/src/index.ts b/sdk/communication/communication-calling-server/src/generated/src/index.ts new file mode 100644 index 000000000000..3eefcc63d80e --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export * from "./models"; +export { CallingServerApiClient } from "./callingServerApiClient"; +export { CallingServerApiClientContext } from "./callingServerApiClientContext"; diff --git a/sdk/communication/communication-calling-server/src/generated/src/models/index.ts b/sdk/communication/communication-calling-server/src/generated/src/models/index.ts new file mode 100644 index 000000000000..d49b3170c066 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/models/index.ts @@ -0,0 +1,1076 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +import * as coreHttp from "@azure/core-http"; + +/** The audio routing group result. */ +export interface AudioRoutingGroupResult { + /** The audio routing mode. */ + audioRoutingMode?: AudioRoutingMode; + /** The target identities that would be receivers in the audio routing group. */ + targets?: CommunicationIdentifierModel[]; +} + +/** Identifies a participant in Azure Communication services. A participant is, for example, a phone number or an Azure communication user. This model must be interpreted as a union: Apart from rawId, at most one further property may be set. */ +export interface CommunicationIdentifierModel { + /** Raw Id of the identifier. Optional in requests, required in responses. */ + rawId?: string; + /** The communication user. */ + communicationUser?: CommunicationUserIdentifierModel; + /** The phone number. */ + phoneNumber?: PhoneNumberIdentifierModel; + /** The Microsoft Teams user. */ + microsoftTeamsUser?: MicrosoftTeamsUserIdentifierModel; +} + +/** A user that got created with an Azure Communication Services resource. */ +export interface CommunicationUserIdentifierModel { + /** The Id of the communication user. */ + id: string; +} + +/** A phone number. */ +export interface PhoneNumberIdentifierModel { + /** The phone number in E.164 format. */ + value: string; +} + +/** A Microsoft Teams user. */ +export interface MicrosoftTeamsUserIdentifierModel { + /** The Id of the Microsoft Teams user. If not anonymous, this is the AAD object Id of the user. */ + userId: string; + /** True if the Microsoft Teams user is anonymous. By default false if missing. */ + isAnonymous?: boolean; + /** The cloud that the Microsoft Teams user belongs to. By default 'public' if missing. */ + cloud?: CommunicationCloudEnvironmentModel; +} + +/** The Communication Services error. */ +export interface CommunicationErrorResponse { + /** The Communication Services error. */ + error: CommunicationError; +} + +/** The Communication Services error. */ +export interface CommunicationError { + /** The error code. */ + code: string; + /** The error message. */ + message: string; + /** + * The error target. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly target?: string; + /** + * Further details about specific errors that led to this error. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly details?: CommunicationError[]; + /** + * The inner error if any. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly innerError?: CommunicationError; +} + +/** The update audio routing group request. */ +export interface UpdateAudioRoutingGroupRequest { + /** The target identities that would be receivers in the audio routing group. */ + targets: CommunicationIdentifierModel[]; +} + +/** The request payload for create call. */ +export interface CreateCallRequest { + /** The alternate identity of the source of the call if dialing out to a pstn number */ + alternateCallerId?: PhoneNumberIdentifierModel; + /** The targets of the call. */ + targets: CommunicationIdentifierModel[]; + /** The source of the call. */ + source: CommunicationIdentifierModel; + /** The subject. */ + subject?: string; + /** The callback URI. */ + callbackUri: string; + /** The requested modalities. */ + requestedMediaTypes?: CallMediaType[]; + /** The requested call events to subscribe to. */ + requestedCallEvents?: CallingEventSubscriptionType[]; +} + +/** The response payload of the create call operation. */ +export interface CreateCallResult { + /** The call connection id. */ + callConnectionId?: string; +} + +export interface CallConnectionProperties { + /** The call connection id. */ + callConnectionId?: string; + /** The source of the call. */ + source?: CommunicationIdentifierModel; + /** The alternate identity of the source of the call if dialing out to a pstn number */ + alternateCallerId?: PhoneNumberIdentifierModel; + /** The targets of the call. */ + targets?: CommunicationIdentifierModel[]; + /** The state of the call connection. */ + callConnectionState?: CallConnectionState; + /** The subject. */ + subject?: string; + /** The callback URI. */ + callbackUri?: string; + /** The requested modalities. */ + requestedMediaTypes?: CallMediaType[]; + /** The requested call events to subscribe to. */ + requestedCallEvents?: CallingEventSubscriptionType[]; + /** The call locator. */ + callLocator?: CallLocatorModel; +} + +/** The locator used for joining or taking action on a call. */ +export interface CallLocatorModel { + /** The group call id */ + groupCallId?: string; + /** The server call id. */ + serverCallId?: string; + /** The call locator kind. */ + kind?: CallLocatorKindModel; +} + +/** The request payload for playing audio. */ +export interface PlayAudioRequest { + /** + * The media resource uri of the play audio request. + * Currently only Wave file (.wav) format audio prompts are supported. + * More specifically, the audio content in the wave file must be mono (single-channel), + * 16-bit samples with a 16,000 (16KHz) sampling rate. + */ + audioFileUri: string; + /** The flag indicating whether audio file needs to be played in loop or not. */ + loop: boolean; + /** The value to identify context of the operation. */ + operationContext?: string; + /** An id for the media in the AudioFileUri, using which we cache the media resource. */ + audioFileId?: string; + /** The callback Uri to receive PlayAudio status notifications. */ + callbackUri?: string; +} + +/** The response payload for play audio operation. */ +export interface PlayAudioResult { + /** The operation id. */ + operationId?: string; + /** The status of the operation */ + status: CallingOperationStatus; + /** The operation context provided by client. */ + operationContext?: string; + /** The result info for the operation. */ + resultInfo?: CallingOperationResultDetails; +} + +/** The result details of calling operation. */ +export interface CallingOperationResultDetails { + /** The result code associated with the operation. */ + code: number; + /** The subcode that further classifies the result. */ + subcode: number; + /** The message is a detail explanation of subcode. */ + message?: string; +} + +/** The transfer call request. */ +export interface TransferCallRequest { + /** The identity of the target where call should be transfer to. */ + targetParticipant?: CommunicationIdentifierModel; + /** The call connection id to replace the current call with. This parameter should be used for consultative transfer. */ + targetCallConnectionId?: string; + /** The alternate identity of the transferor if transferring to a pstn number. */ + alternateCallerId?: PhoneNumberIdentifierModel; + /** The user to user information. */ + userToUserInformation?: string; + /** The operation context. */ + operationContext?: string; +} + +/** The response payload for transfer call operation. */ +export interface TransferCallResult { + /** The operation id. */ + operationId?: string; + /** The status of the operation */ + status: CallingOperationStatus; + /** The operation context provided by client. */ + operationContext?: string; + /** The result info for the operation. */ + resultInfo?: CallingOperationResultDetails; +} + +/** The audio routing group request. */ +export interface AudioRoutingGroupRequest { + /** The audio routing mode. */ + audioRoutingMode: AudioRoutingMode; + /** The target identities that would be receivers in the audio routing group. */ + targets: CommunicationIdentifierModel[]; +} + +/** The response payload of the create audio routing group operation. */ +export interface CreateAudioRoutingGroupResult { + /** The audio routing group id. */ + audioRoutingGroupId?: string; +} + +/** The request payload for get all participants. */ +export interface GetAllParticipantsWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; +} + +/** A participant in a call. */ +export interface CallParticipant { + /** Communication identifier of the participant */ + identifier: CommunicationIdentifierModel; + /** Participant id */ + participantId?: string; + /** Is participant muted */ + isMuted: boolean; +} + +/** The add participant request with call locator. */ +export interface AddParticipantWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The alternate identity of source participant. */ + alternateCallerId?: PhoneNumberIdentifierModel; + /** The participant to be added to the call. */ + participant: CommunicationIdentifierModel; + /** The operation context. */ + operationContext?: string; + /** The callback URI. */ + callbackUri?: string; +} + +/** The add participant result */ +export interface AddParticipantResult { + /** The id of the added participant. */ + participantId?: string; +} + +/** The remove participant by identifier request. */ +export interface RemoveParticipantWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The identifier of the participant to be removed from the call. */ + identifier: CommunicationIdentifierModel; +} + +/** The get participant by identifier request using call locator. */ +export interface GetParticipantWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The identifier of the participant. */ + identifier: CommunicationIdentifierModel; +} + +/** The request payload for playing audio with call locator to participant. */ +export interface PlayAudioToParticipantWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The identifier of the participant to play audio to. */ + identifier: CommunicationIdentifierModel; + /** + * The media resource uri of the play audio request. + * Currently only Wave file (.wav) format audio prompts are supported. + * More specifically, the audio content in the wave file must be mono (single-channel), + * 16-bit samples with a 16,000 (16KHz) sampling rate. + */ + audioFileUri: string; + /** The flag indicating whether audio file needs to be played in loop or not. */ + loop: boolean; + /** The value to identify context of the operation. */ + operationContext?: string; + /** An id for the media in the AudioFileUri, using which we cache the media resource. */ + audioFileId?: string; + /** The callback Uri to receive PlayAudio status notifications. */ + callbackUri?: string; +} + +/** The request payload for stopping a media operation for a participant with call locator. */ +export interface CancelParticipantMediaOperationWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The identifier of the participant. */ + identifier: CommunicationIdentifierModel; + /** The operationId of the media operation to cancel. */ + mediaOperationId: string; +} + +/** The add participant request. */ +export interface AddParticipantRequest { + /** The alternate identity of source participant. */ + alternateCallerId?: PhoneNumberIdentifierModel; + /** The participant to be added to the call. */ + participant: CommunicationIdentifierModel; + /** The operation context. */ + operationContext?: string; + /** The callback URI. */ + callbackUri?: string; +} + +/** The remove participant by identifier request. */ +export interface RemoveParticipantRequest { + /** The identifier of the participant to be removed from the call. */ + identifier: CommunicationIdentifierModel; +} + +/** The get participant by identifier request. */ +export interface GetParticipantRequest { + /** The identifier of the participant. */ + identifier: CommunicationIdentifierModel; +} + +/** The request payload for playing audio to participant. */ +export interface PlayAudioToParticipantRequest { + /** The identifier of the participant to play audio to. */ + identifier: CommunicationIdentifierModel; + /** + * The media resource uri of the play audio request. + * Currently only Wave file (.wav) format audio prompts are supported. + * More specifically, the audio content in the wave file must be mono (single-channel), + * 16-bit samples with a 16,000 (16KHz) sampling rate. + */ + audioFileUri: string; + /** The flag indicating whether audio file needs to be played in loop or not. */ + loop: boolean; + /** The value to identify context of the operation. */ + operationContext?: string; + /** An id for the media in the AudioFileUri, using which we cache the media resource. */ + audioFileId?: string; + /** The callback Uri to receive PlayAudio status notifications. */ + callbackUri?: string; +} + +/** The request payload for stopping a media operation for a participant. */ +export interface CancelParticipantMediaOperationRequest { + /** The identifier of the participant. */ + identifier: CommunicationIdentifierModel; + /** The operationId of the media operation to cancel. */ + mediaOperationId: string; +} + +/** The request payload for muting any participant */ +export interface MuteParticipantRequest { + /** The identifier of the participant to be muted in the call. */ + identifier: CommunicationIdentifierModel; + /** The operation context. */ + operationContext?: string; +} + +/** The request payload for unmuting any participant */ +export interface UnmuteParticipantRequest { + /** The identifier of the participant to be unmuted in the call. */ + identifier: CommunicationIdentifierModel; + /** The operation context. */ + operationContext?: string; +} + +/** The request payload for holding meeting audio for a participant. */ +export interface HoldMeetingAudioRequest { + /** The identifier of the participant. */ + identifier: CommunicationIdentifierModel; +} + +/** The request payload for resuming meeting audio for a participant. */ +export interface ResumeMeetingAudioRequest { + /** The identifier of the participant. */ + identifier: CommunicationIdentifierModel; +} + +/** The request payload start for call recording operation with call locator. */ +export interface StartCallRecordingWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The uri to send notifications to. */ + recordingStateCallbackUri?: string; + /** The content type of call recording. */ + recordingContentType?: RecordingContentType; + /** The channel type of call recording. */ + recordingChannelType?: RecordingChannelType; + /** The format type of call recording. */ + recordingFormatType?: RecordingFormatType; +} + +/** The response payload of start call recording operation. */ +export interface StartCallRecordingResult { + /** The recording id of the started recording */ + recordingId?: string; +} + +/** The response payload of get call recording properties operation. */ +export interface CallRecordingProperties { + /** The state of the recording */ + recordingState: CallRecordingState; +} + +/** The request payload for join call. */ +export interface JoinCallRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The source of the call. */ + source: CommunicationIdentifierModel; + /** The subject. */ + subject?: string; + /** The callback URI. */ + callbackUri: string; + /** The requested modalities. */ + requestedMediaTypes?: CallMediaType[]; + /** The requested call events to subscribe to. */ + requestedCallEvents?: CallingEventSubscriptionType[]; +} + +/** The response payload of the join call operation. */ +export interface JoinCallResult { + /** The call connection id. */ + callConnectionId?: string; +} + +/** The request payload for playing audio with call locator. */ +export interface PlayAudioWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** + * The media resource uri of the play audio request. + * Currently only Wave file (.wav) format audio prompts are supported. + * More specifically, the audio content in the wave file must be mono (single-channel), + * 16-bit samples with a 16,000 (16KHz) sampling rate. + */ + audioFileUri: string; + /** The flag indicating whether audio file needs to be played in loop or not. */ + loop: boolean; + /** The value to identify context of the operation. */ + operationContext?: string; + /** An id for the media in the AudioFileUri, using which we cache the media resource. */ + audioFileId?: string; + /** The callback Uri to receive PlayAudio status notifications. */ + callbackUri?: string; +} + +/** The request payload for stopping a media operation for a participant with call locator. */ +export interface CancelMediaOperationWithCallLocatorRequest { + /** The call locator. */ + callLocator: CallLocatorModel; + /** The operationId of the media operation to cancel */ + mediaOperationId: string; +} + +/** The request payload for answering the call. */ +export interface AnswerCallRequest { + /** The context associated with the call. */ + incomingCallContext: string; + /** The callback uri. */ + callbackUri?: string; + /** The requested modalities. */ + requestedMediaTypes?: CallMediaType[]; + /** The requested call events to subscribe to. */ + requestedCallEvents?: CallingEventSubscriptionType[]; +} + +/** The response payload of the answer call operation. */ +export interface AnswerCallResult { + /** The call connection id. */ + callConnectionId?: string; +} + +/** The request payload for rejecting the call. */ +export interface RejectCallRequest { + /** The context associated with the call. */ + incomingCallContext: string; + /** The rejection reason. */ + callRejectReason?: CallRejectReason; + /** The callback uri. */ + callbackUri?: string; +} + +/** The request payload for redirecting the call. */ +export interface RedirectCallRequest { + /** The context associated with the call. */ + incomingCallContext: string; + /** The target identity to redirect the call to. */ + targets: CommunicationIdentifierModel[]; + /** The callback uri. */ + callbackUri?: string; + /** The timeout for the redirect in seconds. */ + timeoutInSeconds?: number; +} + +/** The call connection state changed event. */ +export interface CallConnectionStateChangedEvent { + /** The server call locator. */ + callLocator?: CallLocatorModel; + /** The call connection id. */ + callConnectionId?: string; + /** The state of the call connection. */ + callConnectionState: CallConnectionState; +} + +/** The call recording state change event. */ +export interface CallRecordingStateChangeEvent { + /** The call recording id */ + recordingId?: string; + /** The state of the recording */ + callRecordingState: CallRecordingState; + /** The time of the recording started */ + startDateTime: Date; + /** The server call locator. */ + callLocator?: CallLocatorModel; +} + +/** The add participant result event. */ +export interface AddParticipantResultEvent { + /** The result details. */ + resultInfo?: CallingOperationResultDetails; + /** The operation context. */ + operationContext?: string; + /** The status of the operation */ + status: CallingOperationStatus; +} + +/** The participant update event */ +export interface ParticipantsUpdatedEvent { + /** The call connection id. */ + callConnectionId?: string; + /** The list of participants. */ + participants?: CallParticipant[]; +} + +/** The play audio result event. */ +export interface PlayAudioResultEvent { + /** The result details. */ + resultInfo?: CallingOperationResultDetails; + /** The operation context. */ + operationContext?: string; + /** The status of the operation */ + status: CallingOperationStatus; +} + +/** The subscribe to tone event */ +export interface ToneReceivedEvent { + /** The tone info. */ + toneInfo: ToneInfo; + /** The call connection id. */ + callConnectionId?: string; +} + +/** The information about the tone. */ +export interface ToneInfo { + /** The sequence id which can be used to determine if the same tone was played multiple times or if any tones were missed. */ + sequenceId: number; + /** The tone value. */ + tone: ToneValue; +} + +/** The transfer call result event. */ +export interface TransferCallResultEvent { + /** The result details. */ + resultInfo?: CallingOperationResultDetails; + /** The operation context. */ + operationContext?: string; + /** The status of the operation */ + status: CallingOperationStatus; +} + +/** Known values of {@link AudioRoutingMode} that the service accepts. */ +export const enum KnownAudioRoutingMode { + OneToOne = "oneToOne", + Multicast = "multicast" +} + +/** + * Defines values for AudioRoutingMode. \ + * {@link KnownAudioRoutingMode} can be used interchangeably with AudioRoutingMode, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **oneToOne** \ + * **multicast** + */ +export type AudioRoutingMode = string; + +/** Known values of {@link CommunicationCloudEnvironmentModel} that the service accepts. */ +export const enum KnownCommunicationCloudEnvironmentModel { + Public = "public", + Dod = "dod", + Gcch = "gcch" +} + +/** + * Defines values for CommunicationCloudEnvironmentModel. \ + * {@link KnownCommunicationCloudEnvironmentModel} can be used interchangeably with CommunicationCloudEnvironmentModel, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **public** \ + * **dod** \ + * **gcch** + */ +export type CommunicationCloudEnvironmentModel = string; + +/** Known values of {@link CallMediaType} that the service accepts. */ +export const enum KnownCallMediaType { + Audio = "audio", + Video = "video" +} + +/** + * Defines values for CallMediaType. \ + * {@link KnownCallMediaType} can be used interchangeably with CallMediaType, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **audio** \ + * **video** + */ +export type CallMediaType = string; + +/** Known values of {@link CallingEventSubscriptionType} that the service accepts. */ +export const enum KnownCallingEventSubscriptionType { + ParticipantsUpdated = "participantsUpdated", + ToneReceived = "toneReceived" +} + +/** + * Defines values for CallingEventSubscriptionType. \ + * {@link KnownCallingEventSubscriptionType} can be used interchangeably with CallingEventSubscriptionType, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **participantsUpdated** \ + * **toneReceived** + */ +export type CallingEventSubscriptionType = string; + +/** Known values of {@link CallConnectionState} that the service accepts. */ +export const enum KnownCallConnectionState { + Connecting = "connecting", + Connected = "connected", + Transferring = "transferring", + TransferAccepted = "transferAccepted", + Disconnecting = "disconnecting", + Disconnected = "disconnected" +} + +/** + * Defines values for CallConnectionState. \ + * {@link KnownCallConnectionState} can be used interchangeably with CallConnectionState, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **connecting** \ + * **connected** \ + * **transferring** \ + * **transferAccepted** \ + * **disconnecting** \ + * **disconnected** + */ +export type CallConnectionState = string; + +/** Known values of {@link CallLocatorKindModel} that the service accepts. */ +export const enum KnownCallLocatorKindModel { + GroupCallLocator = "groupCallLocator", + ServerCallLocator = "serverCallLocator" +} + +/** + * Defines values for CallLocatorKindModel. \ + * {@link KnownCallLocatorKindModel} can be used interchangeably with CallLocatorKindModel, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **groupCallLocator** \ + * **serverCallLocator** + */ +export type CallLocatorKindModel = string; + +/** Known values of {@link CallingOperationStatus} that the service accepts. */ +export const enum KnownCallingOperationStatus { + NotStarted = "notStarted", + Running = "running", + Completed = "completed", + Failed = "failed" +} + +/** + * Defines values for CallingOperationStatus. \ + * {@link KnownCallingOperationStatus} can be used interchangeably with CallingOperationStatus, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **notStarted** \ + * **running** \ + * **completed** \ + * **failed** + */ +export type CallingOperationStatus = string; + +/** Known values of {@link RecordingContentType} that the service accepts. */ +export const enum KnownRecordingContentType { + Audio = "audio", + AudioVideo = "audioVideo" +} + +/** + * Defines values for RecordingContentType. \ + * {@link KnownRecordingContentType} can be used interchangeably with RecordingContentType, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **audio** \ + * **audioVideo** + */ +export type RecordingContentType = string; + +/** Known values of {@link RecordingChannelType} that the service accepts. */ +export const enum KnownRecordingChannelType { + Mixed = "mixed", + Unmixed = "unmixed" +} + +/** + * Defines values for RecordingChannelType. \ + * {@link KnownRecordingChannelType} can be used interchangeably with RecordingChannelType, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **mixed** \ + * **unmixed** + */ +export type RecordingChannelType = string; + +/** Known values of {@link RecordingFormatType} that the service accepts. */ +export const enum KnownRecordingFormatType { + Wav = "wav", + Mp3 = "mp3", + Mp4 = "mp4" +} + +/** + * Defines values for RecordingFormatType. \ + * {@link KnownRecordingFormatType} can be used interchangeably with RecordingFormatType, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **wav** \ + * **mp3** \ + * **mp4** + */ +export type RecordingFormatType = string; + +/** Known values of {@link CallRecordingState} that the service accepts. */ +export const enum KnownCallRecordingState { + Active = "active", + Inactive = "inactive" +} + +/** + * Defines values for CallRecordingState. \ + * {@link KnownCallRecordingState} can be used interchangeably with CallRecordingState, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **active** \ + * **inactive** + */ +export type CallRecordingState = string; + +/** Known values of {@link CallRejectReason} that the service accepts. */ +export const enum KnownCallRejectReason { + None = "none", + Busy = "busy", + Forbidden = "forbidden" +} + +/** + * Defines values for CallRejectReason. \ + * {@link KnownCallRejectReason} can be used interchangeably with CallRejectReason, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **none** \ + * **busy** \ + * **forbidden** + */ +export type CallRejectReason = string; + +/** Known values of {@link ToneValue} that the service accepts. */ +export const enum KnownToneValue { + Tone0 = "tone0", + Tone1 = "tone1", + Tone2 = "tone2", + Tone3 = "tone3", + Tone4 = "tone4", + Tone5 = "tone5", + Tone6 = "tone6", + Tone7 = "tone7", + Tone8 = "tone8", + Tone9 = "tone9", + Star = "star", + Pound = "pound", + A = "a", + B = "b", + C = "c", + D = "d", + Flash = "flash" +} + +/** + * Defines values for ToneValue. \ + * {@link KnownToneValue} can be used interchangeably with ToneValue, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **tone0** \ + * **tone1** \ + * **tone2** \ + * **tone3** \ + * **tone4** \ + * **tone5** \ + * **tone6** \ + * **tone7** \ + * **tone8** \ + * **tone9** \ + * **star** \ + * **pound** \ + * **a** \ + * **b** \ + * **c** \ + * **d** \ + * **flash** + */ +export type ToneValue = string; + +/** Contains response data for the getAudioRoutingGroups operation. */ +export type CallConnectionsGetAudioRoutingGroupsResponse = AudioRoutingGroupResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: AudioRoutingGroupResult; + }; +}; + +/** Contains response data for the createCall operation. */ +export type CallConnectionsCreateCallResponse = CreateCallResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CreateCallResult; + }; +}; + +/** Contains response data for the getCall operation. */ +export type CallConnectionsGetCallResponse = CallConnectionProperties & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CallConnectionProperties; + }; +}; + +/** Contains response data for the playAudio operation. */ +export type CallConnectionsPlayAudioResponse = PlayAudioResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: PlayAudioResult; + }; +}; + +/** Contains response data for the transfer operation. */ +export type CallConnectionsTransferResponse = TransferCallResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: TransferCallResult; + }; +}; + +/** Contains response data for the createAudioRoutingGroup operation. */ +export type CallConnectionsCreateAudioRoutingGroupResponse = CreateAudioRoutingGroupResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CreateAudioRoutingGroupResult; + }; +}; + +/** Contains response data for the getParticipants operation. */ +export type CallConnectionsGetParticipantsResponse = CallParticipant[] & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CallParticipant[]; + }; +}; + +/** Contains response data for the addParticipant operation. */ +export type CallConnectionsAddParticipantResponse = AddParticipantResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: AddParticipantResult; + }; +}; + +/** Contains response data for the getParticipant operation. */ +export type CallConnectionsGetParticipantResponse = CallParticipant[] & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CallParticipant[]; + }; +}; + +/** Contains response data for the participantPlayAudio operation. */ +export type CallConnectionsParticipantPlayAudioResponse = PlayAudioResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: PlayAudioResult; + }; +}; + +/** Contains response data for the getParticipants operation. */ +export type ServerCallsGetParticipantsResponse = CallParticipant[] & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CallParticipant[]; + }; +}; + +/** Contains response data for the addParticipant operation. */ +export type ServerCallsAddParticipantResponse = AddParticipantResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: AddParticipantResult; + }; +}; + +/** Contains response data for the getParticipant operation. */ +export type ServerCallsGetParticipantResponse = CallParticipant[] & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CallParticipant[]; + }; +}; + +/** Contains response data for the participantPlayAudio operation. */ +export type ServerCallsParticipantPlayAudioResponse = PlayAudioResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: PlayAudioResult; + }; +}; + +/** Contains response data for the startRecording operation. */ +export type ServerCallsStartRecordingResponse = StartCallRecordingResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: StartCallRecordingResult; + }; +}; + +/** Contains response data for the getRecordingProperties operation. */ +export type ServerCallsGetRecordingPropertiesResponse = CallRecordingProperties & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: CallRecordingProperties; + }; +}; + +/** Contains response data for the joinCall operation. */ +export type ServerCallsJoinCallResponse = JoinCallResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: JoinCallResult; + }; +}; + +/** Contains response data for the playAudio operation. */ +export type ServerCallsPlayAudioResponse = PlayAudioResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: PlayAudioResult; + }; +}; + +/** Contains response data for the answerCall operation. */ +export type ServerCallsAnswerCallResponse = AnswerCallResult & { + /** The underlying HTTP response. */ + _response: coreHttp.HttpResponse & { + /** The response body as text (string format) */ + bodyAsText: string; + + /** The response body as parsed JSON or XML */ + parsedBody: AnswerCallResult; + }; +}; + +/** Optional parameters. */ +export interface CallingServerApiClientOptionalParams + extends coreHttp.ServiceClientOptions { + /** Api Version */ + apiVersion?: string; + /** Overrides client endpoint. */ + endpoint?: string; +} diff --git a/sdk/communication/communication-calling-server/src/generated/src/models/mappers.ts b/sdk/communication/communication-calling-server/src/generated/src/models/mappers.ts new file mode 100644 index 000000000000..2ae4dd5859a7 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/models/mappers.ts @@ -0,0 +1,1660 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +import * as coreHttp from "@azure/core-http"; + +export const AudioRoutingGroupResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AudioRoutingGroupResult", + modelProperties: { + audioRoutingMode: { + serializedName: "audioRoutingMode", + type: { + name: "String" + } + }, + targets: { + serializedName: "targets", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } + } + } +}; + +export const CommunicationIdentifierModel: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CommunicationIdentifierModel", + modelProperties: { + rawId: { + serializedName: "rawId", + type: { + name: "String" + } + }, + communicationUser: { + serializedName: "communicationUser", + type: { + name: "Composite", + className: "CommunicationUserIdentifierModel" + } + }, + phoneNumber: { + serializedName: "phoneNumber", + type: { + name: "Composite", + className: "PhoneNumberIdentifierModel" + } + }, + microsoftTeamsUser: { + serializedName: "microsoftTeamsUser", + type: { + name: "Composite", + className: "MicrosoftTeamsUserIdentifierModel" + } + } + } + } +}; + +export const CommunicationUserIdentifierModel: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CommunicationUserIdentifierModel", + modelProperties: { + id: { + serializedName: "id", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const PhoneNumberIdentifierModel: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PhoneNumberIdentifierModel", + modelProperties: { + value: { + serializedName: "value", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const MicrosoftTeamsUserIdentifierModel: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "MicrosoftTeamsUserIdentifierModel", + modelProperties: { + userId: { + serializedName: "userId", + required: true, + type: { + name: "String" + } + }, + isAnonymous: { + serializedName: "isAnonymous", + type: { + name: "Boolean" + } + }, + cloud: { + serializedName: "cloud", + type: { + name: "String" + } + } + } + } +}; + +export const CommunicationErrorResponse: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CommunicationErrorResponse", + modelProperties: { + error: { + serializedName: "error", + type: { + name: "Composite", + className: "CommunicationError" + } + } + } + } +}; + +export const CommunicationError: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CommunicationError", + modelProperties: { + code: { + serializedName: "code", + required: true, + type: { + name: "String" + } + }, + message: { + serializedName: "message", + required: true, + type: { + name: "String" + } + }, + target: { + serializedName: "target", + readOnly: true, + type: { + name: "String" + } + }, + details: { + serializedName: "details", + readOnly: true, + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CommunicationError" + } + } + } + }, + innerError: { + serializedName: "innererror", + type: { + name: "Composite", + className: "CommunicationError" + } + } + } + } +}; + +export const UpdateAudioRoutingGroupRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "UpdateAudioRoutingGroupRequest", + modelProperties: { + targets: { + serializedName: "targets", + required: true, + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } + } + } +}; + +export const CreateCallRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CreateCallRequest", + modelProperties: { + alternateCallerId: { + serializedName: "alternateCallerId", + type: { + name: "Composite", + className: "PhoneNumberIdentifierModel" + } + }, + targets: { + serializedName: "targets", + required: true, + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + }, + source: { + serializedName: "source", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + subject: { + serializedName: "subject", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + required: true, + type: { + name: "String" + } + }, + requestedMediaTypes: { + serializedName: "requestedMediaTypes", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + requestedCallEvents: { + serializedName: "requestedCallEvents", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const CreateCallResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CreateCallResult", + modelProperties: { + callConnectionId: { + serializedName: "callConnectionId", + type: { + name: "String" + } + } + } + } +}; + +export const CallConnectionProperties: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CallConnectionProperties", + modelProperties: { + callConnectionId: { + serializedName: "callConnectionId", + type: { + name: "String" + } + }, + source: { + serializedName: "source", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + alternateCallerId: { + serializedName: "alternateCallerId", + type: { + name: "Composite", + className: "PhoneNumberIdentifierModel" + } + }, + targets: { + serializedName: "targets", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + }, + callConnectionState: { + serializedName: "callConnectionState", + type: { + name: "String" + } + }, + subject: { + serializedName: "subject", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + }, + requestedMediaTypes: { + serializedName: "requestedMediaTypes", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + requestedCallEvents: { + serializedName: "requestedCallEvents", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + } + } + } +}; + +export const CallLocatorModel: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CallLocatorModel", + modelProperties: { + groupCallId: { + serializedName: "groupCallId", + type: { + name: "String" + } + }, + serverCallId: { + serializedName: "serverCallId", + type: { + name: "String" + } + }, + kind: { + serializedName: "kind", + type: { + name: "String" + } + } + } + } +}; + +export const PlayAudioRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PlayAudioRequest", + modelProperties: { + audioFileUri: { + serializedName: "audioFileUri", + required: true, + type: { + name: "String" + } + }, + loop: { + serializedName: "loop", + required: true, + type: { + name: "Boolean" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + audioFileId: { + serializedName: "audioFileId", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + } + } + } +}; + +export const PlayAudioResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PlayAudioResult", + modelProperties: { + operationId: { + serializedName: "operationId", + type: { + name: "String" + } + }, + status: { + serializedName: "status", + required: true, + type: { + name: "String" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + resultInfo: { + serializedName: "resultInfo", + type: { + name: "Composite", + className: "CallingOperationResultDetails" + } + } + } + } +}; + +export const CallingOperationResultDetails: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CallingOperationResultDetails", + modelProperties: { + code: { + serializedName: "code", + required: true, + type: { + name: "Number" + } + }, + subcode: { + serializedName: "subcode", + required: true, + type: { + name: "Number" + } + }, + message: { + serializedName: "message", + type: { + name: "String" + } + } + } + } +}; + +export const TransferCallRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "TransferCallRequest", + modelProperties: { + targetParticipant: { + serializedName: "targetParticipant", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + targetCallConnectionId: { + serializedName: "targetCallConnectionId", + type: { + name: "String" + } + }, + alternateCallerId: { + serializedName: "alternateCallerId", + type: { + name: "Composite", + className: "PhoneNumberIdentifierModel" + } + }, + userToUserInformation: { + serializedName: "userToUserInformation", + type: { + name: "String" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + } + } + } +}; + +export const TransferCallResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "TransferCallResult", + modelProperties: { + operationId: { + serializedName: "operationId", + type: { + name: "String" + } + }, + status: { + serializedName: "status", + required: true, + type: { + name: "String" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + resultInfo: { + serializedName: "resultInfo", + type: { + name: "Composite", + className: "CallingOperationResultDetails" + } + } + } + } +}; + +export const AudioRoutingGroupRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AudioRoutingGroupRequest", + modelProperties: { + audioRoutingMode: { + serializedName: "audioRoutingMode", + required: true, + type: { + name: "String" + } + }, + targets: { + serializedName: "targets", + required: true, + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } + } + } +}; + +export const CreateAudioRoutingGroupResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CreateAudioRoutingGroupResult", + modelProperties: { + audioRoutingGroupId: { + serializedName: "audioRoutingGroupId", + type: { + name: "String" + } + } + } + } +}; + +export const GetAllParticipantsWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "GetAllParticipantsWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + } + } + } +}; + +export const CallParticipant: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CallParticipant", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + participantId: { + serializedName: "participantId", + type: { + name: "String" + } + }, + isMuted: { + serializedName: "isMuted", + required: true, + type: { + name: "Boolean" + } + } + } + } +}; + +export const AddParticipantWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AddParticipantWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + alternateCallerId: { + serializedName: "alternateCallerId", + type: { + name: "Composite", + className: "PhoneNumberIdentifierModel" + } + }, + participant: { + serializedName: "participant", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + } + } + } +}; + +export const AddParticipantResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AddParticipantResult", + modelProperties: { + participantId: { + serializedName: "participantId", + type: { + name: "String" + } + } + } + } +}; + +export const RemoveParticipantWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "RemoveParticipantWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } +}; + +export const GetParticipantWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "GetParticipantWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } +}; + +export const PlayAudioToParticipantWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PlayAudioToParticipantWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + audioFileUri: { + serializedName: "audioFileUri", + required: true, + type: { + name: "String" + } + }, + loop: { + serializedName: "loop", + required: true, + type: { + name: "Boolean" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + audioFileId: { + serializedName: "audioFileId", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + } + } + } +}; + +export const CancelParticipantMediaOperationWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CancelParticipantMediaOperationWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + mediaOperationId: { + serializedName: "mediaOperationId", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const AddParticipantRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AddParticipantRequest", + modelProperties: { + alternateCallerId: { + serializedName: "alternateCallerId", + type: { + name: "Composite", + className: "PhoneNumberIdentifierModel" + } + }, + participant: { + serializedName: "participant", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + } + } + } +}; + +export const RemoveParticipantRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "RemoveParticipantRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } +}; + +export const GetParticipantRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "GetParticipantRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } +}; + +export const PlayAudioToParticipantRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PlayAudioToParticipantRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + audioFileUri: { + serializedName: "audioFileUri", + required: true, + type: { + name: "String" + } + }, + loop: { + serializedName: "loop", + required: true, + type: { + name: "Boolean" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + audioFileId: { + serializedName: "audioFileId", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + } + } + } +}; + +export const CancelParticipantMediaOperationRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CancelParticipantMediaOperationRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + mediaOperationId: { + serializedName: "mediaOperationId", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const MuteParticipantRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "MuteParticipantRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + } + } + } +}; + +export const UnmuteParticipantRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "UnmuteParticipantRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + } + } + } +}; + +export const HoldMeetingAudioRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "HoldMeetingAudioRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } +}; + +export const ResumeMeetingAudioRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "ResumeMeetingAudioRequest", + modelProperties: { + identifier: { + serializedName: "identifier", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + } +}; + +export const StartCallRecordingWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "StartCallRecordingWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + recordingStateCallbackUri: { + serializedName: "recordingStateCallbackUri", + type: { + name: "String" + } + }, + recordingContentType: { + serializedName: "recordingContentType", + type: { + name: "String" + } + }, + recordingChannelType: { + serializedName: "recordingChannelType", + type: { + name: "String" + } + }, + recordingFormatType: { + serializedName: "recordingFormatType", + type: { + name: "String" + } + } + } + } +}; + +export const StartCallRecordingResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "StartCallRecordingResult", + modelProperties: { + recordingId: { + serializedName: "recordingId", + type: { + name: "String" + } + } + } + } +}; + +export const CallRecordingProperties: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CallRecordingProperties", + modelProperties: { + recordingState: { + serializedName: "recordingState", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const JoinCallRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "JoinCallRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + source: { + serializedName: "source", + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + }, + subject: { + serializedName: "subject", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + required: true, + type: { + name: "String" + } + }, + requestedMediaTypes: { + serializedName: "requestedMediaTypes", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + requestedCallEvents: { + serializedName: "requestedCallEvents", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const JoinCallResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "JoinCallResult", + modelProperties: { + callConnectionId: { + serializedName: "callConnectionId", + type: { + name: "String" + } + } + } + } +}; + +export const PlayAudioWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PlayAudioWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + audioFileUri: { + serializedName: "audioFileUri", + required: true, + type: { + name: "String" + } + }, + loop: { + serializedName: "loop", + required: true, + type: { + name: "Boolean" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + audioFileId: { + serializedName: "audioFileId", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + } + } + } +}; + +export const CancelMediaOperationWithCallLocatorRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CancelMediaOperationWithCallLocatorRequest", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + mediaOperationId: { + serializedName: "mediaOperationId", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const AnswerCallRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AnswerCallRequest", + modelProperties: { + incomingCallContext: { + serializedName: "incomingCallContext", + required: true, + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + }, + requestedMediaTypes: { + serializedName: "requestedMediaTypes", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + requestedCallEvents: { + serializedName: "requestedCallEvents", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const AnswerCallResult: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AnswerCallResult", + modelProperties: { + callConnectionId: { + serializedName: "callConnectionId", + type: { + name: "String" + } + } + } + } +}; + +export const RejectCallRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "RejectCallRequest", + modelProperties: { + incomingCallContext: { + serializedName: "incomingCallContext", + required: true, + type: { + name: "String" + } + }, + callRejectReason: { + serializedName: "callRejectReason", + type: { + name: "String" + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + } + } + } +}; + +export const RedirectCallRequest: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "RedirectCallRequest", + modelProperties: { + incomingCallContext: { + serializedName: "incomingCallContext", + required: true, + type: { + name: "String" + } + }, + targets: { + serializedName: "targets", + required: true, + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CommunicationIdentifierModel" + } + } + } + }, + callbackUri: { + serializedName: "callbackUri", + type: { + name: "String" + } + }, + timeoutInSeconds: { + serializedName: "timeoutInSeconds", + type: { + name: "Number" + } + } + } + } +}; + +export const CallConnectionStateChangedEvent: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CallConnectionStateChangedEvent", + modelProperties: { + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + }, + callConnectionId: { + serializedName: "callConnectionId", + type: { + name: "String" + } + }, + callConnectionState: { + serializedName: "callConnectionState", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const CallRecordingStateChangeEvent: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "CallRecordingStateChangeEvent", + modelProperties: { + recordingId: { + serializedName: "recordingId", + type: { + name: "String" + } + }, + callRecordingState: { + serializedName: "callRecordingState", + required: true, + type: { + name: "String" + } + }, + startDateTime: { + serializedName: "startDateTime", + required: true, + type: { + name: "DateTime" + } + }, + callLocator: { + serializedName: "callLocator", + type: { + name: "Composite", + className: "CallLocatorModel" + } + } + } + } +}; + +export const AddParticipantResultEvent: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "AddParticipantResultEvent", + modelProperties: { + resultInfo: { + serializedName: "resultInfo", + type: { + name: "Composite", + className: "CallingOperationResultDetails" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + status: { + serializedName: "status", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const ParticipantsUpdatedEvent: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "ParticipantsUpdatedEvent", + modelProperties: { + callConnectionId: { + serializedName: "callConnectionId", + type: { + name: "String" + } + }, + participants: { + serializedName: "participants", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CallParticipant" + } + } + } + } + } + } +}; + +export const PlayAudioResultEvent: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "PlayAudioResultEvent", + modelProperties: { + resultInfo: { + serializedName: "resultInfo", + type: { + name: "Composite", + className: "CallingOperationResultDetails" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + status: { + serializedName: "status", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const ToneReceivedEvent: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "ToneReceivedEvent", + modelProperties: { + toneInfo: { + serializedName: "toneInfo", + type: { + name: "Composite", + className: "ToneInfo" + } + }, + callConnectionId: { + serializedName: "callConnectionId", + type: { + name: "String" + } + } + } + } +}; + +export const ToneInfo: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "ToneInfo", + modelProperties: { + sequenceId: { + serializedName: "sequenceId", + required: true, + type: { + name: "Number" + } + }, + tone: { + serializedName: "tone", + required: true, + type: { + name: "String" + } + } + } + } +}; + +export const TransferCallResultEvent: coreHttp.CompositeMapper = { + type: { + name: "Composite", + className: "TransferCallResultEvent", + modelProperties: { + resultInfo: { + serializedName: "resultInfo", + type: { + name: "Composite", + className: "CallingOperationResultDetails" + } + }, + operationContext: { + serializedName: "operationContext", + type: { + name: "String" + } + }, + status: { + serializedName: "status", + required: true, + type: { + name: "String" + } + } + } + } +}; diff --git a/sdk/communication/communication-calling-server/src/generated/src/models/parameters.ts b/sdk/communication/communication-calling-server/src/generated/src/models/parameters.ts new file mode 100644 index 000000000000..e6e750b1c622 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/models/parameters.ts @@ -0,0 +1,258 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +import { + OperationParameter, + OperationURLParameter, + OperationQueryParameter +} from "@azure/core-http"; +import { + UpdateAudioRoutingGroupRequest as UpdateAudioRoutingGroupRequestMapper, + CreateCallRequest as CreateCallRequestMapper, + PlayAudioRequest as PlayAudioRequestMapper, + TransferCallRequest as TransferCallRequestMapper, + AudioRoutingGroupRequest as AudioRoutingGroupRequestMapper, + AddParticipantRequest as AddParticipantRequestMapper, + RemoveParticipantRequest as RemoveParticipantRequestMapper, + GetParticipantRequest as GetParticipantRequestMapper, + PlayAudioToParticipantRequest as PlayAudioToParticipantRequestMapper, + CancelParticipantMediaOperationRequest as CancelParticipantMediaOperationRequestMapper, + MuteParticipantRequest as MuteParticipantRequestMapper, + UnmuteParticipantRequest as UnmuteParticipantRequestMapper, + HoldMeetingAudioRequest as HoldMeetingAudioRequestMapper, + ResumeMeetingAudioRequest as ResumeMeetingAudioRequestMapper, + GetAllParticipantsWithCallLocatorRequest as GetAllParticipantsWithCallLocatorRequestMapper, + AddParticipantWithCallLocatorRequest as AddParticipantWithCallLocatorRequestMapper, + RemoveParticipantWithCallLocatorRequest as RemoveParticipantWithCallLocatorRequestMapper, + GetParticipantWithCallLocatorRequest as GetParticipantWithCallLocatorRequestMapper, + PlayAudioToParticipantWithCallLocatorRequest as PlayAudioToParticipantWithCallLocatorRequestMapper, + CancelParticipantMediaOperationWithCallLocatorRequest as CancelParticipantMediaOperationWithCallLocatorRequestMapper, + StartCallRecordingWithCallLocatorRequest as StartCallRecordingWithCallLocatorRequestMapper, + JoinCallRequest as JoinCallRequestMapper, + PlayAudioWithCallLocatorRequest as PlayAudioWithCallLocatorRequestMapper, + CancelMediaOperationWithCallLocatorRequest as CancelMediaOperationWithCallLocatorRequestMapper, + AnswerCallRequest as AnswerCallRequestMapper, + RejectCallRequest as RejectCallRequestMapper, + RedirectCallRequest as RedirectCallRequestMapper +} from "../models/mappers"; + +export const accept: OperationParameter = { + parameterPath: "accept", + mapper: { + defaultValue: "application/json", + isConstant: true, + serializedName: "Accept", + type: { + name: "String" + } + } +}; + +export const endpoint: OperationURLParameter = { + parameterPath: "endpoint", + mapper: { + serializedName: "endpoint", + required: true, + type: { + name: "String" + } + }, + skipEncoding: true +}; + +export const callConnectionId: OperationURLParameter = { + parameterPath: "callConnectionId", + mapper: { + serializedName: "callConnectionId", + required: true, + type: { + name: "String" + } + } +}; + +export const audioRoutingGroupId: OperationURLParameter = { + parameterPath: "audioRoutingGroupId", + mapper: { + serializedName: "audioRoutingGroupId", + required: true, + type: { + name: "String" + } + } +}; + +export const apiVersion: OperationQueryParameter = { + parameterPath: "apiVersion", + mapper: { + defaultValue: "2021-11-15-preview", + isConstant: true, + serializedName: "api-version", + type: { + name: "String" + } + } +}; + +export const contentType: OperationParameter = { + parameterPath: ["options", "contentType"], + mapper: { + defaultValue: "application/json", + isConstant: true, + serializedName: "Content-Type", + type: { + name: "String" + } + } +}; + +export const updateAudioRoutingGroupRequest: OperationParameter = { + parameterPath: "updateAudioRoutingGroupRequest", + mapper: UpdateAudioRoutingGroupRequestMapper +}; + +export const callRequest: OperationParameter = { + parameterPath: "callRequest", + mapper: CreateCallRequestMapper +}; + +export const playAudioRequest: OperationParameter = { + parameterPath: "playAudioRequest", + mapper: PlayAudioRequestMapper +}; + +export const transferCallRequest: OperationParameter = { + parameterPath: "transferCallRequest", + mapper: TransferCallRequestMapper +}; + +export const audioRoutingGroupRequest: OperationParameter = { + parameterPath: "audioRoutingGroupRequest", + mapper: AudioRoutingGroupRequestMapper +}; + +export const addParticipantRequest: OperationParameter = { + parameterPath: "addParticipantRequest", + mapper: AddParticipantRequestMapper +}; + +export const removeParticipantRequest: OperationParameter = { + parameterPath: "removeParticipantRequest", + mapper: RemoveParticipantRequestMapper +}; + +export const getParticipantRequest: OperationParameter = { + parameterPath: "getParticipantRequest", + mapper: GetParticipantRequestMapper +}; + +export const playAudioToParticipantRequest: OperationParameter = { + parameterPath: "playAudioToParticipantRequest", + mapper: PlayAudioToParticipantRequestMapper +}; + +export const cancelMediaOperationRequest: OperationParameter = { + parameterPath: "cancelMediaOperationRequest", + mapper: CancelParticipantMediaOperationRequestMapper +}; + +export const muteParticipantRequest: OperationParameter = { + parameterPath: "muteParticipantRequest", + mapper: MuteParticipantRequestMapper +}; + +export const unmuteParticipantRequest: OperationParameter = { + parameterPath: "unmuteParticipantRequest", + mapper: UnmuteParticipantRequestMapper +}; + +export const holdMeetingAudioRequest: OperationParameter = { + parameterPath: "holdMeetingAudioRequest", + mapper: HoldMeetingAudioRequestMapper +}; + +export const resumeMeetingAudioRequest: OperationParameter = { + parameterPath: "resumeMeetingAudioRequest", + mapper: ResumeMeetingAudioRequestMapper +}; + +export const getAllParticipantsWithCallLocatorRequest: OperationParameter = { + parameterPath: "getAllParticipantsWithCallLocatorRequest", + mapper: GetAllParticipantsWithCallLocatorRequestMapper +}; + +export const addParticipantWithCallLocatorRequest: OperationParameter = { + parameterPath: "addParticipantWithCallLocatorRequest", + mapper: AddParticipantWithCallLocatorRequestMapper +}; + +export const removeParticipantWithCallLocatorRequest: OperationParameter = { + parameterPath: "removeParticipantWithCallLocatorRequest", + mapper: RemoveParticipantWithCallLocatorRequestMapper +}; + +export const getParticipantWithCallLocatorRequest: OperationParameter = { + parameterPath: "getParticipantWithCallLocatorRequest", + mapper: GetParticipantWithCallLocatorRequestMapper +}; + +export const playAudioToParticipantRequest1: OperationParameter = { + parameterPath: "playAudioToParticipantRequest", + mapper: PlayAudioToParticipantWithCallLocatorRequestMapper +}; + +export const cancelParticipantMediaOperationRequest: OperationParameter = { + parameterPath: "cancelParticipantMediaOperationRequest", + mapper: CancelParticipantMediaOperationWithCallLocatorRequestMapper +}; + +export const startCallRecordingWithCallLocatorRequest: OperationParameter = { + parameterPath: "startCallRecordingWithCallLocatorRequest", + mapper: StartCallRecordingWithCallLocatorRequestMapper +}; + +export const recordingId: OperationURLParameter = { + parameterPath: "recordingId", + mapper: { + serializedName: "recordingId", + required: true, + type: { + name: "String" + } + } +}; + +export const callRequest1: OperationParameter = { + parameterPath: "callRequest", + mapper: JoinCallRequestMapper +}; + +export const playAudioRequest1: OperationParameter = { + parameterPath: "playAudioRequest", + mapper: PlayAudioWithCallLocatorRequestMapper +}; + +export const cancelMediaOperationRequest1: OperationParameter = { + parameterPath: "cancelMediaOperationRequest", + mapper: CancelMediaOperationWithCallLocatorRequestMapper +}; + +export const answerCallRequest: OperationParameter = { + parameterPath: "answerCallRequest", + mapper: AnswerCallRequestMapper +}; + +export const rejectCallRequest: OperationParameter = { + parameterPath: "rejectCallRequest", + mapper: RejectCallRequestMapper +}; + +export const redirectCallRequest: OperationParameter = { + parameterPath: "redirectCallRequest", + mapper: RedirectCallRequestMapper +}; diff --git a/sdk/communication/communication-calling-server/src/generated/src/operations/callConnections.ts b/sdk/communication/communication-calling-server/src/generated/src/operations/callConnections.ts new file mode 100644 index 000000000000..a51911cb4adb --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/operations/callConnections.ts @@ -0,0 +1,1274 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +import * as coreHttp from "@azure/core-http"; +import * as Mappers from "../models/mappers"; +import * as Parameters from "../models/parameters"; +import { CallingServerApiClientContext } from "../callingServerApiClientContext"; +import { + CallConnectionsGetAudioRoutingGroupsResponse, + UpdateAudioRoutingGroupRequest, + CreateCallRequest, + CallConnectionsCreateCallResponse, + CallConnectionsGetCallResponse, + PlayAudioRequest, + CallConnectionsPlayAudioResponse, + TransferCallRequest, + CallConnectionsTransferResponse, + AudioRoutingGroupRequest, + CallConnectionsCreateAudioRoutingGroupResponse, + CallConnectionsGetParticipantsResponse, + AddParticipantRequest, + CallConnectionsAddParticipantResponse, + RemoveParticipantRequest, + GetParticipantRequest, + CallConnectionsGetParticipantResponse, + PlayAudioToParticipantRequest, + CallConnectionsParticipantPlayAudioResponse, + CancelParticipantMediaOperationRequest, + MuteParticipantRequest, + UnmuteParticipantRequest, + HoldMeetingAudioRequest, + ResumeMeetingAudioRequest +} from "../models"; + +/** Class representing a CallConnections. */ +export class CallConnections { + private readonly client: CallingServerApiClientContext; + + /** + * Initialize a new instance of the class CallConnections class. + * @param client Reference to the service client + */ + constructor(client: CallingServerApiClientContext) { + this.client = client; + } + + /** + * Get audio routing groups from a call. + * @param callConnectionId The call connection id. + * @param audioRoutingGroupId The audio routing group id. + * @param options The options parameters. + */ + getAudioRoutingGroups( + callConnectionId: string, + audioRoutingGroupId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + audioRoutingGroupId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + getAudioRoutingGroupsOperationSpec + ) as Promise; + } + + /** + * Delete audio routing group from a call. + * @param callConnectionId The call connection id. + * @param audioRoutingGroupId The audio routing group id. + * @param options The options parameters. + */ + deleteAudioRoutingGroup( + callConnectionId: string, + audioRoutingGroupId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + audioRoutingGroupId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + deleteAudioRoutingGroupOperationSpec + ) as Promise; + } + + /** + * Update audio routing group. + * @param callConnectionId The call connection id. + * @param audioRoutingGroupId The audio routing group id. + * @param updateAudioRoutingGroupRequest The update audio routing group request. + * @param options The options parameters. + */ + updateAudioRoutingGroup( + callConnectionId: string, + audioRoutingGroupId: string, + updateAudioRoutingGroupRequest: UpdateAudioRoutingGroupRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + audioRoutingGroupId, + updateAudioRoutingGroupRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + updateAudioRoutingGroupOperationSpec + ) as Promise; + } + + /** + * Create a new call. + * @param callRequest Create call request. + * @param options The options parameters. + */ + createCall( + callRequest: CreateCallRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + createCallOperationSpec + ) as Promise; + } + + /** + * Get call connection. + * @param callConnectionId The call connection id. + * @param options The options parameters. + */ + getCall( + callConnectionId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + getCallOperationSpec + ) as Promise; + } + + /** + * Delete the call. + * @param callConnectionId The call connection id. + * @param options The options parameters. + */ + deleteCall( + callConnectionId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + deleteCallOperationSpec + ) as Promise; + } + + /** + * Hangup the call. + * @param callConnectionId The call connection id. + * @param options The options parameters. + */ + hangupCall( + callConnectionId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + hangupCallOperationSpec + ) as Promise; + } + + /** + * Play audio in the call. + * @param callConnectionId The call connection id. + * @param playAudioRequest The play audio request. + * @param options The options parameters. + */ + playAudio( + callConnectionId: string, + playAudioRequest: PlayAudioRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + playAudioRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + playAudioOperationSpec + ) as Promise; + } + + /** + * Cancel all media operations. + * @param callConnectionId The call connection id + * @param options The options parameters. + */ + cancelAllMediaOperations( + callConnectionId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + cancelAllMediaOperationsOperationSpec + ) as Promise; + } + + /** + * Keep the call alive. + * @param callConnectionId The call connection id. + * @param options The options parameters. + */ + keepAlive( + callConnectionId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + keepAliveOperationSpec + ) as Promise; + } + + /** + * Transfer the call to a participant or to another call. + * @param callConnectionId The call connection id. + * @param transferCallRequest The transfer call request. + * @param options The options parameters. + */ + transfer( + callConnectionId: string, + transferCallRequest: TransferCallRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + transferCallRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + transferOperationSpec + ) as Promise; + } + + /** + * Create audio routing group in a call. + * @param callConnectionId The call connection id. + * @param audioRoutingGroupRequest The audio routing group request. + * @param options The options parameters. + */ + createAudioRoutingGroup( + callConnectionId: string, + audioRoutingGroupRequest: AudioRoutingGroupRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + audioRoutingGroupRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + createAudioRoutingGroupOperationSpec + ) as Promise; + } + + /** + * Get participants from a call. + * @param callConnectionId The call connection id. + * @param options The options parameters. + */ + getParticipants( + callConnectionId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + getParticipantsOperationSpec + ) as Promise; + } + + /** + * Add a participant to the call. + * @param callConnectionId The call connection id. + * @param addParticipantRequest Add participant request. + * @param options The options parameters. + */ + addParticipant( + callConnectionId: string, + addParticipantRequest: AddParticipantRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + addParticipantRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + addParticipantOperationSpec + ) as Promise; + } + + /** + * Remove participant from the call using identifier. + * @param callConnectionId The call connection id. + * @param removeParticipantRequest The identifier of the participant to be removed from the call. + * @param options The options parameters. + */ + removeParticipant( + callConnectionId: string, + removeParticipantRequest: RemoveParticipantRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + removeParticipantRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + removeParticipantOperationSpec + ) as Promise; + } + + /** + * Get participant from the call using identifier. + * @param callConnectionId The call connection id. + * @param getParticipantRequest The identifier of the participant to get from the call. + * @param options The options parameters. + */ + getParticipant( + callConnectionId: string, + getParticipantRequest: GetParticipantRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + getParticipantRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + getParticipantOperationSpec + ) as Promise; + } + + /** + * Play audio to a participant. + * @param callConnectionId The callConnectionId. + * @param playAudioToParticipantRequest The play audio to participant request. + * @param options The options parameters. + */ + participantPlayAudio( + callConnectionId: string, + playAudioToParticipantRequest: PlayAudioToParticipantRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + playAudioToParticipantRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + participantPlayAudioOperationSpec + ) as Promise; + } + + /** + * Cancel media operation for a participant. + * @param callConnectionId The callConnectionId. + * @param cancelMediaOperationRequest The cancel media operation for participant request. + * @param options The options parameters. + */ + cancelParticipantMediaOperation( + callConnectionId: string, + cancelMediaOperationRequest: CancelParticipantMediaOperationRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + cancelMediaOperationRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + cancelParticipantMediaOperationOperationSpec + ) as Promise; + } + + /** + * Mute participant in the call + * @param callConnectionId The call connection id. + * @param muteParticipantRequest The identifier of the participant to mute in the call. + * @param options The options parameters. + */ + muteParticipant( + callConnectionId: string, + muteParticipantRequest: MuteParticipantRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + muteParticipantRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + muteParticipantOperationSpec + ) as Promise; + } + + /** + * Unmute participant in the call + * @param callConnectionId The call connection id. + * @param unmuteParticipantRequest The identifier of the participant to unmute in the call. + * @param options The options parameters. + */ + unmuteParticipant( + callConnectionId: string, + unmuteParticipantRequest: UnmuteParticipantRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + unmuteParticipantRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + unmuteParticipantOperationSpec + ) as Promise; + } + + /** + * Hold meeting audio of a participant in the call. + * @param callConnectionId The call connection id. + * @param holdMeetingAudioRequest The request payload for holding meeting audio for a participant. + * @param options The options parameters. + */ + holdParticipantMeetingAudio( + callConnectionId: string, + holdMeetingAudioRequest: HoldMeetingAudioRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + holdMeetingAudioRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + holdParticipantMeetingAudioOperationSpec + ) as Promise; + } + + /** + * Resume meeting audio of a participant in the call. + * @param callConnectionId The call connection id. + * @param resumeMeetingAudioRequest The request payload for resuming meeting audio for a participant. + * @param options The options parameters. + */ + resumeParticipantMeetingAudio( + callConnectionId: string, + resumeMeetingAudioRequest: ResumeMeetingAudioRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callConnectionId, + resumeMeetingAudioRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + resumeParticipantMeetingAudioOperationSpec + ) as Promise; + } +} +// Operation Specifications +const serializer = new coreHttp.Serializer(Mappers, /* isXml */ false); + +const getAudioRoutingGroupsOperationSpec: coreHttp.OperationSpec = { + path: + "/calling/callConnections/{callConnectionId}/audioRoutingGroups/{audioRoutingGroupId}", + httpMethod: "GET", + responses: { + 200: { + bodyMapper: Mappers.AudioRoutingGroupResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [ + Parameters.endpoint, + Parameters.callConnectionId, + Parameters.audioRoutingGroupId + ], + headerParameters: [Parameters.accept], + serializer +}; +const deleteAudioRoutingGroupOperationSpec: coreHttp.OperationSpec = { + path: + "/calling/callConnections/{callConnectionId}/audioRoutingGroups/{audioRoutingGroupId}", + httpMethod: "DELETE", + responses: { + 202: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [ + Parameters.endpoint, + Parameters.callConnectionId, + Parameters.audioRoutingGroupId + ], + headerParameters: [Parameters.accept], + serializer +}; +const updateAudioRoutingGroupOperationSpec: coreHttp.OperationSpec = { + path: + "/calling/callConnections/{callConnectionId}/audioRoutingGroups/{audioRoutingGroupId}", + httpMethod: "PATCH", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.updateAudioRoutingGroupRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [ + Parameters.endpoint, + Parameters.callConnectionId, + Parameters.audioRoutingGroupId + ], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const createCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections", + httpMethod: "POST", + responses: { + 201: { + bodyMapper: Mappers.CreateCallResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.callRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const getCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}", + httpMethod: "GET", + responses: { + 200: { + bodyMapper: Mappers.CallConnectionProperties + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept], + serializer +}; +const deleteCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}", + httpMethod: "DELETE", + responses: { + 202: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept], + serializer +}; +const hangupCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/:hangup", + httpMethod: "POST", + responses: { + 202: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept], + serializer +}; +const playAudioOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/:playAudio", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.PlayAudioResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.playAudioRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const cancelAllMediaOperationsOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/:cancelAllMediaOperations", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept], + serializer +}; +const keepAliveOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/:keepAlive", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept], + serializer +}; +const transferOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/:transfer", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.TransferCallResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.transferCallRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const createAudioRoutingGroupOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/:createAudioRoutingGroup", + httpMethod: "POST", + responses: { + 201: { + bodyMapper: Mappers.CreateAudioRoutingGroupResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.audioRoutingGroupRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const getParticipantsOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/participants", + httpMethod: "GET", + responses: { + 200: { + bodyMapper: { + type: { + name: "Sequence", + element: { type: { name: "Composite", className: "CallParticipant" } } + } + } + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept], + serializer +}; +const addParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/participants", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.AddParticipantResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.addParticipantRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const removeParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/participants:remove", + httpMethod: "POST", + responses: { + 202: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.removeParticipantRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const getParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/participants:get", + httpMethod: "POST", + responses: { + 200: { + bodyMapper: { + type: { + name: "Sequence", + element: { type: { name: "Composite", className: "CallParticipant" } } + } + } + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.getParticipantRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const participantPlayAudioOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/participants:playAudio", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.PlayAudioResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.playAudioToParticipantRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const cancelParticipantMediaOperationOperationSpec: coreHttp.OperationSpec = { + path: + "/calling/callConnections/{callConnectionId}/participants:cancelMediaOperation", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.cancelMediaOperationRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const muteParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/participants:mute", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.muteParticipantRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const unmuteParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/callConnections/{callConnectionId}/participants:unmute", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.unmuteParticipantRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const holdParticipantMeetingAudioOperationSpec: coreHttp.OperationSpec = { + path: + "/calling/callConnections/{callConnectionId}/participants:holdMeetingAudio", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.holdMeetingAudioRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const resumeParticipantMeetingAudioOperationSpec: coreHttp.OperationSpec = { + path: + "/calling/callConnections/{callConnectionId}/participants:resumeMeetingAudio", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.resumeMeetingAudioRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.callConnectionId], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; diff --git a/sdk/communication/communication-calling-server/src/generated/src/operations/index.ts b/sdk/communication/communication-calling-server/src/generated/src/operations/index.ts new file mode 100644 index 000000000000..404a44c57f54 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/operations/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export * from "./callConnections"; +export * from "./serverCalls"; diff --git a/sdk/communication/communication-calling-server/src/generated/src/operations/serverCalls.ts b/sdk/communication/communication-calling-server/src/generated/src/operations/serverCalls.ts new file mode 100644 index 000000000000..ba3d6ba75d7f --- /dev/null +++ b/sdk/communication/communication-calling-server/src/generated/src/operations/serverCalls.ts @@ -0,0 +1,954 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +import * as coreHttp from "@azure/core-http"; +import * as Mappers from "../models/mappers"; +import * as Parameters from "../models/parameters"; +import { CallingServerApiClientContext } from "../callingServerApiClientContext"; +import { + GetAllParticipantsWithCallLocatorRequest, + ServerCallsGetParticipantsResponse, + AddParticipantWithCallLocatorRequest, + ServerCallsAddParticipantResponse, + RemoveParticipantWithCallLocatorRequest, + GetParticipantWithCallLocatorRequest, + ServerCallsGetParticipantResponse, + PlayAudioToParticipantWithCallLocatorRequest, + ServerCallsParticipantPlayAudioResponse, + CancelParticipantMediaOperationWithCallLocatorRequest, + StartCallRecordingWithCallLocatorRequest, + ServerCallsStartRecordingResponse, + ServerCallsGetRecordingPropertiesResponse, + JoinCallRequest, + ServerCallsJoinCallResponse, + PlayAudioWithCallLocatorRequest, + ServerCallsPlayAudioResponse, + CancelMediaOperationWithCallLocatorRequest, + AnswerCallRequest, + ServerCallsAnswerCallResponse, + RejectCallRequest, + RedirectCallRequest +} from "../models"; + +/** Class representing a ServerCalls. */ +export class ServerCalls { + private readonly client: CallingServerApiClientContext; + + /** + * Initialize a new instance of the class ServerCalls class. + * @param client Reference to the service client + */ + constructor(client: CallingServerApiClientContext) { + this.client = client; + } + + /** + * Get participants from a server call. + * @param getAllParticipantsWithCallLocatorRequest The request payload for getting all the + * participants. + * @param options The options parameters. + */ + getParticipants( + getAllParticipantsWithCallLocatorRequest: GetAllParticipantsWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + getAllParticipantsWithCallLocatorRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + getParticipantsOperationSpec + ) as Promise; + } + + /** + * Add a participant to the call. + * @param addParticipantWithCallLocatorRequest The add participant request using call locator. + * @param options The options parameters. + */ + addParticipant( + addParticipantWithCallLocatorRequest: AddParticipantWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + addParticipantWithCallLocatorRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + addParticipantOperationSpec + ) as Promise; + } + + /** + * Remove participant from the call using identifier. + * @param removeParticipantWithCallLocatorRequest The identifier of the participant to be removed from + * the call. + * @param options The options parameters. + */ + removeParticipant( + removeParticipantWithCallLocatorRequest: RemoveParticipantWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + removeParticipantWithCallLocatorRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + removeParticipantOperationSpec + ) as Promise; + } + + /** + * Get participant from the call using identifier. + * @param getParticipantWithCallLocatorRequest The get participant request. + * @param options The options parameters. + */ + getParticipant( + getParticipantWithCallLocatorRequest: GetParticipantWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + getParticipantWithCallLocatorRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + getParticipantOperationSpec + ) as Promise; + } + + /** + * Play audio to a participant. + * @param playAudioToParticipantRequest The play audio to participant request. + * @param options The options parameters. + */ + participantPlayAudio( + playAudioToParticipantRequest: PlayAudioToParticipantWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + playAudioToParticipantRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + participantPlayAudioOperationSpec + ) as Promise; + } + + /** + * cancel media operation for a participant. + * @param cancelParticipantMediaOperationRequest The cancel participant media operation request + * @param options The options parameters. + */ + cancelParticipantMediaOperation( + cancelParticipantMediaOperationRequest: CancelParticipantMediaOperationWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + cancelParticipantMediaOperationRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + cancelParticipantMediaOperationOperationSpec + ) as Promise; + } + + /** + * Start recording the call. + * @param startCallRecordingWithCallLocatorRequest The request body of start call recording request. + * @param options The options parameters. + */ + startRecording( + startCallRecordingWithCallLocatorRequest: StartCallRecordingWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + startCallRecordingWithCallLocatorRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + startRecordingOperationSpec + ) as Promise; + } + + /** + * Get call recording properties. + * @param recordingId The recording id. + * @param options The options parameters. + */ + getRecordingProperties( + recordingId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + recordingId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + getRecordingPropertiesOperationSpec + ) as Promise; + } + + /** + * Stop recording the call. + * @param recordingId The recording id. + * @param options The options parameters. + */ + stopRecording( + recordingId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + recordingId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + stopRecordingOperationSpec + ) as Promise; + } + + /** + * Pause recording the call. + * @param recordingId The recording id. + * @param options The options parameters. + */ + pauseRecording( + recordingId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + recordingId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + pauseRecordingOperationSpec + ) as Promise; + } + + /** + * Resume recording the call. + * @param recordingId The recording id. + * @param options The options parameters. + */ + resumeRecording( + recordingId: string, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + recordingId, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + resumeRecordingOperationSpec + ) as Promise; + } + + /** + * Join a call. + * @param callRequest The join call request. + * @param options The options parameters. + */ + joinCall( + callRequest: JoinCallRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + callRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + joinCallOperationSpec + ) as Promise; + } + + /** + * Play audio in the call. + * @param playAudioRequest Play audio request. + * @param options The options parameters. + */ + playAudio( + playAudioRequest: PlayAudioWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + playAudioRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + playAudioOperationSpec + ) as Promise; + } + + /** + * cancel media operation. + * @param cancelMediaOperationRequest The cancel media operation request + * @param options The options parameters. + */ + cancelMediaOperation( + cancelMediaOperationRequest: CancelMediaOperationWithCallLocatorRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + cancelMediaOperationRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + cancelMediaOperationOperationSpec + ) as Promise; + } + + /** + * Answer the call. + * @param answerCallRequest The answer call request. + * @param options The options parameters. + */ + answerCall( + answerCallRequest: AnswerCallRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + answerCallRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + answerCallOperationSpec + ) as Promise; + } + + /** + * Reject the call. + * @param rejectCallRequest The reject call request. + * @param options The options parameters. + */ + rejectCall( + rejectCallRequest: RejectCallRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + rejectCallRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + rejectCallOperationSpec + ) as Promise; + } + + /** + * Redirect the call. + * @param redirectCallRequest The redirect call request. + * @param options The options parameters. + */ + redirectCall( + redirectCallRequest: RedirectCallRequest, + options?: coreHttp.OperationOptions + ): Promise { + const operationArguments: coreHttp.OperationArguments = { + redirectCallRequest, + options: coreHttp.operationOptionsToRequestOptionsBase(options || {}) + }; + return this.client.sendOperationRequest( + operationArguments, + redirectCallOperationSpec + ) as Promise; + } +} +// Operation Specifications +const serializer = new coreHttp.Serializer(Mappers, /* isXml */ false); + +const getParticipantsOperationSpec: coreHttp.OperationSpec = { + path: "/calling/participants:getAll", + httpMethod: "POST", + responses: { + 200: { + bodyMapper: { + type: { + name: "Sequence", + element: { type: { name: "Composite", className: "CallParticipant" } } + } + } + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.getAllParticipantsWithCallLocatorRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const addParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/participants", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.AddParticipantResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.addParticipantWithCallLocatorRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const removeParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/participants:remove", + httpMethod: "POST", + responses: { + 202: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.removeParticipantWithCallLocatorRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const getParticipantOperationSpec: coreHttp.OperationSpec = { + path: "/calling/participants:get", + httpMethod: "POST", + responses: { + 200: { + bodyMapper: { + type: { + name: "Sequence", + element: { type: { name: "Composite", className: "CallParticipant" } } + } + } + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.getParticipantWithCallLocatorRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const participantPlayAudioOperationSpec: coreHttp.OperationSpec = { + path: "/calling/participants:playAudio", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.PlayAudioResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.playAudioToParticipantRequest1, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const cancelParticipantMediaOperationOperationSpec: coreHttp.OperationSpec = { + path: "/calling/participants:cancelMediaOperation", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.cancelParticipantMediaOperationRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const startRecordingOperationSpec: coreHttp.OperationSpec = { + path: "/calling/recordings", + httpMethod: "POST", + responses: { + 200: { + bodyMapper: Mappers.StartCallRecordingResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.startCallRecordingWithCallLocatorRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const getRecordingPropertiesOperationSpec: coreHttp.OperationSpec = { + path: "/calling/recordings/{recordingId}", + httpMethod: "GET", + responses: { + 200: { + bodyMapper: Mappers.CallRecordingProperties + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.recordingId], + headerParameters: [Parameters.accept], + serializer +}; +const stopRecordingOperationSpec: coreHttp.OperationSpec = { + path: "/calling/recordings/{recordingId}", + httpMethod: "DELETE", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.recordingId], + headerParameters: [Parameters.accept], + serializer +}; +const pauseRecordingOperationSpec: coreHttp.OperationSpec = { + path: "/calling/recordings/{recordingId}/:pause", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.recordingId], + headerParameters: [Parameters.accept], + serializer +}; +const resumeRecordingOperationSpec: coreHttp.OperationSpec = { + path: "/calling/recordings/{recordingId}/:resume", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint, Parameters.recordingId], + headerParameters: [Parameters.accept], + serializer +}; +const joinCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling:join", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.JoinCallResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.callRequest1, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const playAudioOperationSpec: coreHttp.OperationSpec = { + path: "/calling:playAudio", + httpMethod: "POST", + responses: { + 202: { + bodyMapper: Mappers.PlayAudioResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.playAudioRequest1, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const cancelMediaOperationOperationSpec: coreHttp.OperationSpec = { + path: "/calling:cancelMediaOperation", + httpMethod: "POST", + responses: { + 200: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.cancelMediaOperationRequest1, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const answerCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling:answer", + httpMethod: "POST", + responses: { + 201: { + bodyMapper: Mappers.AnswerCallResult + }, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.answerCallRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const rejectCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling:reject", + httpMethod: "POST", + responses: { + 202: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.rejectCallRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; +const redirectCallOperationSpec: coreHttp.OperationSpec = { + path: "/calling:redirect", + httpMethod: "POST", + responses: { + 202: {}, + 400: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 401: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 403: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 404: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + }, + 500: { + bodyMapper: Mappers.CommunicationErrorResponse, + isError: true + } + }, + requestBody: Parameters.redirectCallRequest, + queryParameters: [Parameters.apiVersion], + urlParameters: [Parameters.endpoint], + headerParameters: [Parameters.accept, Parameters.contentType], + mediaType: "json", + serializer +}; diff --git a/sdk/communication/communication-calling-server/src/index.ts b/sdk/communication/communication-calling-server/src/index.ts new file mode 100644 index 000000000000..9be21d326c17 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/index.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import { HttpResponse } from "@azure/core-http"; + +export * from "./models"; +export * from "./parameters"; +export * from "./callingServerClient"; +export { CallConnection } from "./callConnection"; +export { ContentDownloader } from "./ContentDownloader"; +export { TokenCredential } from "@azure/core-auth"; + +/** Defines headers for Content download operation. */ +export interface ContentDownloadHeaders { + /** The number of bytes present in the response body. */ + contentLength?: number; + /** The media type of the body of the response. For Download Blob this is 'application/octet-stream' */ + contentType?: string; + /** Indicates the range of bytes returned in the event that the client requested a subset of the blob by setting the 'Range' request header. */ + contentRange?: string; + /** UTC date/time value generated by the service that indicates the time at which the response was initiated */ + date?: Date; + /** Error Code */ + errorCode?: string; +} + +/** Contains response data for the download operation. */ +export type ContentDownloadResponse = ContentDownloadHeaders & { + /** + * BROWSER ONLY + * + * The response body as a browser Blob. + * Always `undefined` in node.js. + */ + blobBody?: Promise; + /** + * NODEJS ONLY + * + * The response body as a node.js Readable stream. + * Always `undefined` in the browser. + */ + readableStreamBody?: NodeJS.ReadableStream; + + /** The underlying HTTP response. */ + _response: HttpResponse & { + /** The parsed HTTP response headers. */ + parsedHeaders: ContentDownloadHeaders; + }; +}; diff --git a/sdk/communication/communication-calling-server/src/logger.ts b/sdk/communication/communication-calling-server/src/logger.ts new file mode 100644 index 000000000000..56a3fcf9d6ef --- /dev/null +++ b/sdk/communication/communication-calling-server/src/logger.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { createClientLogger } from "@azure/logger"; + +export const logger = createClientLogger("communication-calling-server"); diff --git a/sdk/communication/communication-calling-server/src/mappers.ts b/sdk/communication/communication-calling-server/src/mappers.ts new file mode 100644 index 000000000000..6ea03dcb7136 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/mappers.ts @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { CompositeMapper } from "@azure/core-http"; + +export const ContentDownloadHeaders: CompositeMapper = { + serializedName: "Content_downloadHeaders", + type: { + name: "Composite", + className: "ContentDownloadHeaders", + modelProperties: { + contentLength: { + serializedName: "content-length", + xmlName: "content-length", + type: { + name: "Number" + } + }, + contentType: { + serializedName: "content-type", + xmlName: "content-type", + type: { + name: "String" + } + }, + contentRange: { + serializedName: "content-range", + xmlName: "content-range", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + xmlName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + xmlName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; diff --git a/sdk/communication/communication-calling-server/src/models.ts b/sdk/communication/communication-calling-server/src/models.ts new file mode 100644 index 000000000000..bdeb4e0cdf82 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/models.ts @@ -0,0 +1,316 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import { AbortSignalLike } from "@azure/abort-controller"; +import { OperationOptions, TransferProgressEvent } from "@azure/core-http"; +import { PhoneNumberIdentifier } from "@azure/communication-common"; + +import { + CallMediaType, + CallingEventSubscriptionType, + RecordingContentType, + RecordingChannelType, + RecordingFormatType +} from "./generated/src/"; + +export { + CallLocatorKindModel, + CallLocatorModel, + CallMediaType, + CallConnectionState, + CallRecordingState, + CallingEventSubscriptionType, + CallingOperationStatus, + CallingOperationResultDetails, + CallRecordingProperties, + PlayAudioResult, + PlayAudioResultEvent, + AddParticipantResult, + StartCallRecordingResult, + ToneReceivedEvent, + AddParticipantResultEvent, + CallConnectionStateChangedEvent, + ToneValue, + ToneInfo, + ServerCallsAddParticipantResponse, + CallConnectionsAddParticipantResponse, + CallConnectionsPlayAudioResponse, + RecordingContentType, + RecordingChannelType, + RecordingFormatType +} from "./generated/src/models"; + +/** + * Options to create a call. + */ +export interface CreateCallConnectionOptions extends OperationOptions { + /** The alternate identity of the source of the call if dialing out to a pstn number */ + alternateCallerId?: PhoneNumberIdentifier; + /** The subject. */ + subject?: string; + /** The callback URI. */ + callbackUri: string; + /** The requested modalities. */ + requestedMediaTypes: CallMediaType[]; + /** The requested call events to subscribe to. */ + requestedCallEvents: CallingEventSubscriptionType[]; +} + +/** + * Options to join a call. + */ +export interface JoinCallOptions extends OperationOptions { + /** The subject. */ + subject?: string; + /** The callback URI. */ + callbackUri: string; + /** The requested modalities. */ + requestedMediaTypes?: CallMediaType[]; + /** The requested call events to subscribe to. */ + requestedCallEvents?: CallingEventSubscriptionType[]; +} + +/** + * Options to play audio. + */ +export interface PlayAudioOptions extends OperationOptions { + /** The flag indicating whether audio file needs to be played in loop or not. */ + loop: boolean; + /** The value to identify context of the operation. */ + operationContext: string; + /** An id for the media in the AudioFileUri, using which we cache the media resource. */ + audioFileId: string; + /** The callback Uri to receive PlayAudio status notifications. */ + callbackUri: string; +} + +/** + * Options to play audio to participant. + */ +export type PlayAudioToParticipantOptions = PlayAudioOptions; + +/** + * Options to add participant to the call. + */ +export interface AddParticipantOptions extends OperationOptions { + /** The phone number to use when adding a pstn participant. */ + alternateCallerId?: string; + /** The operation context. */ + operationContext?: string; +} + +/** + * Options to remove participant from the call. + */ +export type RemoveParticipantOptions = OperationOptions; + +/** + * Options to cancel media operation in the call. + */ +export type CancelMediaOperationOptions = OperationOptions; + +/** + * Options to hang up a call. + */ +export type HangUpOptions = OperationOptions; + +/** + * Options to cancel all media operations. + */ +export type CancelAllMediaOperationsOptions = OperationOptions; + +/** + * Options to transfer call. + */ +export type TransferCallOptions = OperationOptions; + +/** + * Options to start recording. + */ +export interface StartRecordingOptions extends OperationOptions { + /** The content type of call recording. */ + recordingContentType?: RecordingContentType; + + /** The channel type of call recording. */ + recordingChannelType?: RecordingChannelType; + + /** The format type of call recording. */ + recordingFormatType?: RecordingFormatType; +} +/** + * Options to pause recording. + */ +export type PauseRecordingOptions = OperationOptions; +/** + * Options to resume recording. + */ +export type ResumeRecordingOptions = OperationOptions; +/** + * Options to stop recording. + */ +export type StopRecordingOptions = OperationOptions; +/** + * Options to get recording properties. + */ +export type GetRecordingPropertiesOptions = OperationOptions; +/** + * Options to delete recording. + */ +export type DeleteOptions = OperationOptions; + +/** + * Call Locator. + */ +export type CallLocator = GroupCallLocator | ServerCallLocator; + +/** + * The group call locator. + */ +export interface GroupCallLocator { + /** + * The group call id. + */ + groupCallId: string; +} + +/** + * An Azure Communication user. + */ +export interface ServerCallLocator { + /** + * The server call id. + */ + serverCallId: string; +} + +/** + * Tests an locator to determine whether it implements GroupCallLocator. + * + * @param locator - The assumed GroupCallLocator to be tested. + */ +export const isGroupCallLocator = (locator: CallLocator): locator is GroupCallLocator => { + return typeof (locator as any).groupCallId === "string"; +}; + +/** + * Tests an locator to determine whether it implements ServerCallLocator. + * + * @param locator - The assumed ServerCallLocator to be tested. + */ +export const isServerCallLocator = (locator: CallLocator): locator is ServerCallLocator => { + return typeof (locator as any).serverCallId === "string"; +}; + +/** + * The CallLocatorKind is a discriminated union that adds a property `kind` to an CallLocator. + */ +export type CallLocatorKind = GroupCallLocatorKind | ServerCallLocatorKind; + +/** + * LocatorKind for a GroupCallLocator. + */ +export interface GroupCallLocatorKind extends GroupCallLocator { + /** + * The locator kind. + */ + kind: "groupCall"; +} + +/** + * LocatorKind for ServerCallLocator. + */ +export interface ServerCallLocatorKind extends ServerCallLocator { + /** + * The locator kind. + */ + kind: "serverCall"; +} + +/** + * Returns the CallLocatorKind for a given CallLocator. Returns undefined if the kind couldn't be inferred. + * + * @param locator - The locator whose kind is to be inferred. + */ +export const getLocatorKind = (locator: CallLocator): CallLocatorKind => { + if (isGroupCallLocator(locator)) { + return { ...locator, kind: "groupCall" }; + } + if (isServerCallLocator(locator)) { + return { ...locator, kind: "serverCall" }; + } + throw "unknow CallLocator type."; +}; + +/** The options parameters for download api. */ +export interface DownloadOptions extends OperationOptions { + /** + * An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation. + * For example, use the @azure/abort-controller to create an `AbortSignal`. + */ + abortSignal?: AbortSignalLike; + /** + * Call back to receive events on the progress of download operation. + */ + onProgress?: (progress: TransferProgressEvent) => void; + + /** + * Optional. ONLY AVAILABLE IN NODE.JS. + * + * How many retries will perform when original body download stream unexpected ends. + * Above kind of ends will not trigger retry policy defined in a pipeline, + * because they doesn't emit network errors. + * + * With this option, every additional retry means an additional `FileClient.download()` request will be made + * from the broken point, until the requested range has been successfully downloaded or maxRetryRequests is reached. + * + * Default value is 5, please set a larger value when loading large files in poor network. + */ + maxRetryRequests?: number; + + /** + * Optional. + * + * How much data to be downloaded, greater than 0. Will download to the end when undefined + */ + count?: number; +} + +/** The options parameters for downloadContent api. */ +export interface DownloadContentOptions extends DownloadOptions { + /** Return only the bytes of the blob in the specified range. */ + range?: string; +} + +/** Values of {@link CallingServerEventType} that the service accepts. */ +export enum CallingServerEventTypeValue { + /** The call connection state change event type. */ + CallConnectionStateChangedEvent = "Microsoft.Communication.CallConnectionStateChanged", + + /** The add participant result event type. */ + AddParticipantResultEvent = "Microsoft.Communication.AddParticipantResult", + + /** The call recording state change event type. */ + CallRecordingStateChangedEvent = "Microsoft.Communication.CallRecordingStateChanged", + + /** The play audio result event type. */ + PlayAudioResultEvent = "Microsoft.Communication.PlayAudioResult", + + /** The participants updated event type. */ + ParticipantsUpdatedEvent = "Microsoft.Communication.ParticipantsUpdated", + + /** The subscribe to tone event type. */ + ToneReceivedEvent = "Microsoft.Communication.ToneReceived" +} + +/** + * Defines values for CallingServerEventType. + * {@link CallingServerEventTypeValue} can be used interchangeably with CallingServerEventType, + * this enum contains the known values that the service supports. + * ### Know values supported by the service + * **Microsoft.Communication.CallConnectionStateChanged** + * **Microsoft.Communication.AddParticipantResult** + * **Microsoft.Communication.CallRecordingStateChanged** + * **Microsoft.Communication.PlayAudioResult** + * **Microsoft.Communication.ParticipantsUpdated** + * **Microsoft.Communication.ToneReceived** + */ +export type CallingServerEventType = string; diff --git a/sdk/communication/communication-calling-server/src/parameters.ts b/sdk/communication/communication-calling-server/src/parameters.ts new file mode 100644 index 000000000000..3b33579d2c0e --- /dev/null +++ b/sdk/communication/communication-calling-server/src/parameters.ts @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + */ + +import { OperationParameter } from "@azure/core-http"; + +/** Specified range used to indicate the bytes of the blob. */ +export const range: OperationParameter = { + parameterPath: ["options", "range"], + mapper: { + serializedName: "x-ms-range", + xmlName: "x-ms-range", + type: { + name: "String" + } + } +}; diff --git a/sdk/communication/communication-calling-server/src/tracing.ts b/sdk/communication/communication-calling-server/src/tracing.ts new file mode 100644 index 000000000000..24246e150c1c --- /dev/null +++ b/sdk/communication/communication-calling-server/src/tracing.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { OperationOptions, RequestOptionsBase } from "@azure/core-http"; +import { createSpanFunction } from "@azure/core-tracing"; + +/** + * Creates a span using the global tracer. + * @internal + */ +export const createSpan = createSpanFunction({ + packagePrefix: "Azure.Communication", + namespace: "Microsoft.Communication" +}); + +/** + * @internal + * + * Adapt the tracing options from OperationOptions to what they need to be for + * RequestOptionsBase (when we update to later OpenTelemetry versions this is now + * two separate fields, not just one). + */ +export function convertTracingToRequestOptionsBase( + options?: OperationOptions +): Pick { + return { + spanOptions: options?.tracingOptions?.spanOptions, + tracingContext: options?.tracingOptions?.tracingContext + }; +} diff --git a/sdk/communication/communication-calling-server/src/utils/RetriableReadableStream.ts b/sdk/communication/communication-calling-server/src/utils/RetriableReadableStream.ts new file mode 100644 index 000000000000..badd4b428cd2 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/utils/RetriableReadableStream.ts @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { TransferProgressEvent } from "@azure/core-http"; +import { Readable } from "stream"; + +export type ReadableStreamGetter = (offset: number) => Promise; + +export interface RetriableReadableStreamOptions { + /** + * Max retry count (greater than or equal to 0), undefined or invalid value means no retry + */ + maxRetryRequests?: number; + + /** + * Read progress event handler + */ + onProgress?: (progress: TransferProgressEvent) => void; + + /** + * Debug purpose only. Used to inject an unexpected end to existing internal stream, + * to test stream retry works well or not. + * + * When assign it to true, for next incoming "data" event of internal stream, + * RetriableReadableStream will try to emit an "end" event to existing internal + * stream to force it end and start retry from the breaking point. + * The value will then update to "undefined", once the injection works. + */ + doInjectErrorOnce?: boolean; + + /** + * A threshold, not a limit. Dictates the amount of data that a stream buffers before it stops asking for more data. + */ + highWaterMark?: number; +} + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * A Node.js ReadableStream will internally retry when internal ReadableStream unexpected ends. + */ +export class RetriableReadableStream extends Readable { + private start: number; + private offset: number; + private end: number; + private getter: ReadableStreamGetter; + private source: NodeJS.ReadableStream; + private retries: number = 0; + private maxRetryRequests: number; + private onProgress?: (progress: TransferProgressEvent) => void; + private options: RetriableReadableStreamOptions; + + /** + * Creates an instance of RetriableReadableStream. + * + * @param source - The current ReadableStream returned from getter + * @param getter - A method calling downloading request returning + * a new ReadableStream from specified offset + * @param offset - Offset position in original data source to read + * @param count - How much data in original data source to read + * @param options - + */ + public constructor( + source: NodeJS.ReadableStream, + getter: ReadableStreamGetter, + offset: number, + count: number, + options: RetriableReadableStreamOptions = {} + ) { + super({ highWaterMark: options.highWaterMark }); + this.getter = getter; + this.source = source; + this.start = offset; + this.offset = offset; + this.end = offset + count - 1; + this.maxRetryRequests = + options.maxRetryRequests && options.maxRetryRequests >= 0 ? options.maxRetryRequests : 0; + this.onProgress = options.onProgress; + this.options = options; + + this.setSourceEventHandlers(); + } + + public _read(): void { + this.source.resume(); + } + + private setSourceEventHandlers(): void { + this.source.on("data", this.sourceDataHandler); + this.source.on("end", this.sourceErrorOrEndHandler); + this.source.on("error", this.sourceErrorOrEndHandler); + } + + private removeSourceEventHandlers(): void { + this.source.removeListener("data", this.sourceDataHandler); + this.source.removeListener("end", this.sourceErrorOrEndHandler); + this.source.removeListener("error", this.sourceErrorOrEndHandler); + } + + private sourceDataHandler = (data: Buffer): void => { + if (this.options.doInjectErrorOnce) { + this.options.doInjectErrorOnce = undefined; + this.source.pause(); + this.source.removeAllListeners("data"); + this.source.emit("end"); + return; + } + + // console.log( + // `Offset: ${this.offset}, Received ${data.length} from internal stream` + // ); + this.offset += data.length; + if (this.onProgress) { + this.onProgress({ loadedBytes: this.offset - this.start }); + } + if (!this.push(data)) { + this.source.pause(); + } + }; + + private sourceErrorOrEndHandler = (err?: Error): void => { + if (err && err.name === "AbortError") { + this.destroy(err); + return; + } + + // console.log( + // `Source stream emits end or error, offset: ${ + // this.offset + // }, dest end : ${this.end}` + // ); + this.removeSourceEventHandlers(); + if (this.offset - 1 === this.end) { + this.push(null); + } else if (this.offset <= this.end) { + // console.log( + // `retries: ${this.retries}, max retries: ${this.maxRetries}` + // ); + if (this.retries < this.maxRetryRequests) { + this.retries += 1; + this.getter(this.offset) + .then((newSource) => { + this.source = newSource; + this.setSourceEventHandlers(); + return; + }) + .catch((error) => { + this.destroy(error); + }); + } else { + this.destroy( + new Error( + // tslint:disable-next-line:max-line-length + `Data corruption failure: received less data than required and reached maxRetires limitation. Received data offset: ${this + .offset - 1}, data needed offset: ${this.end}, retries: ${ + this.retries + }, max retries: ${this.maxRetryRequests}` + ) + ); + } + } else { + this.destroy( + new Error( + `Data corruption failure: Received more data than original request, data needed offset is ${ + this.end + }, received offset: ${this.offset - 1}` + ) + ); + } + }; + + _destroy(error: Error | null, callback: (error?: Error) => void): void { + // remove listener from source and release source + this.removeSourceEventHandlers(); + (this.source as Readable).destroy(); + + callback(error === null ? undefined : error); + } +} diff --git a/sdk/communication/communication-calling-server/src/utils/base64.ts b/sdk/communication/communication-calling-server/src/utils/base64.ts new file mode 100644 index 000000000000..01585e3675c4 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/utils/base64.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { isNode } from "@azure/core-http"; + +/** + * Base64 encode. + * + * @internal + * @param content - string need to be encoded + */ +export function base64encode(content: string): string { + return isNode ? Buffer.from(content).toString("base64") : btoa(content); +} + +/** + * Base64 decode. + * + * @internal + * @param encodedString - string need to be decoded + */ +export function base64decode(encodedString: string): string { + return isNode ? Buffer.from(encodedString, "base64").toString() : atob(encodedString); +} diff --git a/sdk/communication/communication-calling-server/src/utils/utils.ts b/sdk/communication/communication-calling-server/src/utils/utils.ts new file mode 100644 index 000000000000..dd72df897ae6 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/utils/utils.ts @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { OperationQueryParameter } from "@azure/core-http"; +import { URLBuilder } from "@azure/core-http"; + +export class CallingServerUtils { + public static isValidUrl(urlToVerify: string): boolean { + let url; + try { + url = URLBuilder.parse(urlToVerify); + } catch (_) { + return false; + } + return url.getScheme() === "http" || url.getScheme() === "https"; + } + + public static getStringToSignHeader(stringToSign: string): OperationQueryParameter { + return { + parameterPath: "UriToSignWith", + mapper: { + defaultValue: stringToSign, + isConstant: true, + serializedName: "UriToSignWith", + type: { + name: "String" + } + } + }; + } + + public static getMsHostHeaders(hostName: string): OperationQueryParameter { + const q = URLBuilder.parse(hostName!); + const hostAndPort = q.getHost()! + (q.getPort() !== undefined ? q.getPort() : ""); + return { + parameterPath: "x-ms-host", + mapper: { + defaultValue: hostAndPort, + isConstant: true, + serializedName: "x-ms-host", + type: { + name: "String" + } + } + }; + } + + public static getStringToSign(resourceEndpoint: string, requestUri: string): string { + const q = URLBuilder.parse(requestUri); + const formattedUrl = q.getPath()!.startsWith("/") ? q.getPath()!.substr(1) : q.getPath()!; + return resourceEndpoint + formattedUrl; + } +} diff --git a/sdk/communication/communication-calling-server/src/uuid.ts b/sdk/communication/communication-calling-server/src/uuid.ts new file mode 100644 index 000000000000..c6cf92396ce3 --- /dev/null +++ b/sdk/communication/communication-calling-server/src/uuid.ts @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { generateUuid } from "@azure/core-http"; + +// This is used as a workaround to be able to stub generateUuid +// during testing. +export class Uuid { + public static generateUuid(): string { + return generateUuid(); + } +} diff --git a/sdk/communication/communication-calling-server/swagger/README.md b/sdk/communication/communication-calling-server/swagger/README.md new file mode 100644 index 000000000000..57206e50c01f --- /dev/null +++ b/sdk/communication/communication-calling-server/swagger/README.md @@ -0,0 +1,32 @@ +# Azure Communication Services CallingServer Protocol Layer + +> see [https://aka.ms/autorest](https://aka.ms/autorest) + +### Generation + +```ps +cd +rushx build:autorest +``` + +## Configuration + +```yaml +package-name: azure-communication-calling-server +title: CallingServerApiClient +description: CallingServer Client +generate-metadata: false +license-header: MICROSOFT_MIT_NO_VERSION +output-folder: ../src/generated +tag: package-2021-11-15-preview +require: https://raw.githubusercontent.com/navali-msft/azure-rest-api-specs/773f9b008157ff125fa339b23eab534308e61d3f/specification/communication/data-plane/CallingServer/readme.md +model-date-time-as-string: false +optional-response-headers: true +typescript: true +azure-arm: false +add-credentials: false +disable-async-iterators: true +use-extension: + "@autorest/typescript": "6.0.0-dev.20210217.1" +package-version: 1.0.0-beta.1 +``` diff --git a/sdk/communication/communication-calling-server/test.env b/sdk/communication/communication-calling-server/test.env new file mode 100644 index 000000000000..745b49828b9f --- /dev/null +++ b/sdk/communication/communication-calling-server/test.env @@ -0,0 +1,5 @@ +COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING="endpoint=;accessKey=" + +# Our tests assume that TEST_MODE is "playback" by default. You can +# change it to "record" to generate new recordings, or "live" to bypass the recorder entirely. +# TEST_MODE=record diff --git a/sdk/communication/communication-calling-server/test/README.md b/sdk/communication/communication-calling-server/test/README.md new file mode 100644 index 000000000000..f3a54253ada2 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/README.md @@ -0,0 +1,19 @@ +# Testing + +To test this project, make sure to build it by following our [building instructions](https://github.com/Azure/azure-sdk-for-js/blob/main/CONTRIBUTING.md#building), then follow the [testing instructions](https://github.com/Azure/azure-sdk-for-js/blob/main/CONTRIBUTING.md#testing). + +You can use existing Azure resources for the live tests, or generate new ones by using our [New-TestResources.ps1](https://github.com/Azure/azure-sdk-for-js/blob/main/eng/common/TestResources/New-TestResources.ps1) script, which will use an [ARM template](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/communication/test-resources.json) that already has all of the the necessary configurations. + +The Azure resource that is used by the tests in this project is: + +- An existing Communication Services resource. If you need to create the resource, you can use the [Azure Portal][azure_portal] or [Azure CLI][azure_cli]. + +To run the live tests, you will need to set the below environment variables: + +- `TEST_MODE`: Should have `live` assigned if you want to run live without recording. Assign `record` to run live with recording. +- `COMMUNICATION_LIVETEST_DYNAMIC_CONNECTION_STRING`: The primary connection string of the Communication Services resource in your account. + +[azure_sub]: https://azure.microsoft.com/free/ +[azure_portal]: https://portal.azure.com + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js%2Fsdk%2Fcommunication%2Fcommunication-identity%2FREADME.png) diff --git a/sdk/communication/communication-calling-server/test/internal/serverCall.internal.spec.ts b/sdk/communication/communication-calling-server/test/internal/serverCall.internal.spec.ts new file mode 100644 index 000000000000..b8a9b37806d4 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/internal/serverCall.internal.spec.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import { assert } from "chai"; +import { CallingServerClient, ServerCallLocator } from "../../src"; + +describe("ServerCall", function() { + describe("Recording", function() { + it("Start recording with relative url fails", async () => { + const connectionString = + "endpoint=https://REDACTED.communication.azure.com/;accesskey=eyJhbG=="; + const serverCallId = + "aHR0cHM6Ly9jb252LXVzd2UtMDguY29udi5za3lwZS5jb20vY29udi8tby1FWjVpMHJrS3RFTDBNd0FST1J3P2k9ODgmZT02Mzc1Nzc0MTY4MDc4MjQyOTM"; + const callingServerClient = new CallingServerClient(connectionString); + const callLocator: ServerCallLocator = { serverCallId: serverCallId }; + + try { + await callingServerClient.startRecording(callLocator, "/not/absolute/uri"); + } catch (e) { + assert.equal((e as Error).message, "recordingStateCallbackUri is invalid."); + } + }); + }); +}); diff --git a/sdk/communication/communication-calling-server/test/public/callConnection.spec.ts b/sdk/communication/communication-calling-server/test/public/callConnection.spec.ts new file mode 100644 index 000000000000..bfedc58e66f0 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/callConnection.spec.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { env, record, Recorder, RecorderEnvironmentSetup } from "@azure-tools/test-recorder"; +import { CallingServerClient, CreateCallConnectionOptions, PlayAudioOptions } from "../../src"; +import { TestUtils } from "./utils/testUtils"; +import { Context } from "mocha"; +import * as Constants from "./utils/constants"; +import { CommunicationIdentityClient } from "@azure/communication-identity"; +import { PhoneNumberIdentifier } from "@azure/communication-common"; +const replaceableVariables: { [k: string]: string } = { + COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING: "endpoint=https://endpoint/;accesskey=banana", + AZURE_PHONE_NUMBER: "+15551234567" +}; + +const environmentSetup: RecorderEnvironmentSetup = { + replaceableVariables, + customizationsOnRecordings: [ + (recording: string): string => recording.replace(/(https:\/\/)([^/',]*)/, "$1endpoint"), + (recording: string): string => recording.replace("endpoint:443", "endpoint") + ], + queryParametersToSkip: [] +}; + +describe("Call Connection Live Test", function() { + describe("Call Automation Operations", function() { + let recorder: Recorder; + let connectionString: string; + + beforeEach(async function(this: Context) { + recorder = record(this, environmentSetup); + /* Place your code here*/ + connectionString = env.COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING; + }); + + afterEach(async function(this: Context) { + if (!this.currentTest?.isPending()) { + await recorder.stop(); + } + }); + + it("Run create_play_cancel_hangup scenario", async function(this: Context) { + this.timeout(0); + // this.callingServer = createCallingServerClient(); + // this.callingServer = createSmsClient(); + const to_phone_number = env.AZURE_PHONE_NUMBER; + const callingServer = new CallingServerClient(connectionString); + const identityClient = new CommunicationIdentityClient(connectionString); + const from_user = await identityClient.createUser(); + const to_user: PhoneNumberIdentifier = { + phoneNumber: to_phone_number + }; + const from_phone_number = "+18445764430"; + // create call option + const createCallOptions: CreateCallConnectionOptions = { + callbackUri: Constants.CALLBACK_URI, + requestedMediaTypes: ["audio"], + requestedCallEvents: ["participantsUpdated", "toneReceived"], + alternateCallerId: { phoneNumber: from_phone_number } + }; + const callConnection = await callingServer.createCallConnection( + from_user, + [to_user], + createCallOptions + ); + try { + // create PlayAudio option + const playAudioOptions: PlayAudioOptions = { + loop: true, + audioFileId: recorder.getUniqueName("audioFileId"), + callbackUri: Constants.CALLBACK_URI, + operationContext: recorder.getUniqueName("operationContext") + }; + await TestUtils.delayIfLive(); + await callConnection.playAudio(Constants.Audio_File_Url, playAudioOptions); + await callConnection.cancelAllMediaOperations(); + await TestUtils.delayIfLive(); + } finally { + await callConnection.hangUp(); + } + }); + }); +}); diff --git a/sdk/communication/communication-calling-server/test/public/deleteContent.spec.ts b/sdk/communication/communication-calling-server/test/public/deleteContent.spec.ts new file mode 100644 index 000000000000..53b1128b0737 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/deleteContent.spec.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + env, + isPlaybackMode, + record, + Recorder, + RecorderEnvironmentSetup +} from "@azure-tools/test-recorder"; +import { assert } from "chai"; +import { CallingServerClient } from "../../src"; +import { Context } from "mocha"; +import { RestError } from "@azure/core-http"; + +const replaceableVariables: { [k: string]: string } = { + COMMUNICATION_LIVETEST_DYNAMIC_CONNECTION_STRING: "endpoint=https://endpoint/;accesskey=banana" +}; + +const environmentSetup: RecorderEnvironmentSetup = { + replaceableVariables, + customizationsOnRecordings: [ + (recording: string): string => recording.replace(/(https:\/\/)([^/',]*)/, "$1endpoint"), + (recording: string): string => recording.replace("endpoint:443", "endpoint") + ], + queryParametersToSkip: [] +}; + +describe("Delete Live Tests", function() { + let recorder: Recorder; + const uri = "https://endpoint/v1/objects/0-wus-d6-fdf8ff0fdcd668bca8c52c0b1ee79b05"; + const invalidUri = "https://endpoint/v1/objects/0-wus-d4-ca4017a32f8514aa9f054f0917270000"; + + const callingServerServiceClient = new CallingServerClient( + env.COMMUNICATION_LIVETEST_DYNAMIC_CONNECTION_STRING || + "endpoint=https://endpoint/;accesskey=banana" + ); + + beforeEach(async function(this: Context) { + recorder = record(this, environmentSetup); + }); + + afterEach(async function(this: Context) { + if (!this.currentTest?.isPending()) { + await recorder.stop(); + } + }); + + it("delete", async function(this: Context) { + if (!isPlaybackMode()) { + // tslint:disable-next-line:no-invalid-this + this.skip(); + } + + const result = await callingServerServiceClient.delete(uri); + assert.equal(200, result._response.status); + }); + + it("unauthorized delete", async function(this: Context) { + if (!isPlaybackMode()) { + // tslint:disable-next-l ine:no-invalid-this + this.skip(); + } + + try { + const unauthorizedCallingServerServiceClient = new CallingServerClient( + "endpoint=https://test.communication.azure.com/;accesskey=1234" + ); + await unauthorizedCallingServerServiceClient.delete(uri); + } catch (e) { + assert.equal((e as RestError).statusCode, 401); + } + }); + + it("invalid file delete", async function(this: Context) { + if (!isPlaybackMode()) { + // tslint:disable-next-line:no-invalid-this + this.skip(); + } + try { + await callingServerServiceClient.download(invalidUri); + } catch (e) { + assert.equal((e as RestError).statusCode, 404); + } + }); +}); diff --git a/sdk/communication/communication-calling-server/test/public/downloadContent.spec.ts b/sdk/communication/communication-calling-server/test/public/downloadContent.spec.ts new file mode 100644 index 000000000000..46c9fd168d39 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/downloadContent.spec.ts @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + isPlaybackMode, + record, + Recorder, + RecorderEnvironmentSetup +} from "@azure-tools/test-recorder"; +import { assert } from "chai"; +import { CallingServerClient } from "../../src"; +import { Context } from "mocha"; +import { bodyToString } from "./utils"; +import { RestError } from "@azure/core-http"; + +const replaceableVariables: { [k: string]: string } = { + COMMUNICATION_LIVETEST_DYNAMIC_CONNECTION_STRING: "endpoint=https://endpoint/;accesskey=banana" +}; + +const environmentSetup: RecorderEnvironmentSetup = { + replaceableVariables, + customizationsOnRecordings: [ + (recording: string): string => recording.replace(/(https:\/\/)([^/',]*)/, "$1endpoint"), + (recording: string): string => recording.replace("endpoint:443", "endpoint") + ], + queryParametersToSkip: [] +}; + +describe("Download Content", function() { + let recorder: Recorder; + const uri = + "https://endpoint/v1/objects/0-eus-d15-af5689148b0afa252a57a0121b744dcd/content/acsmetadata"; + const callingServerServiceClient = new CallingServerClient( + "endpoint=https://endpoint/;accesskey=banana" + ); + + beforeEach(async function(this: Context) { + recorder = record(this, environmentSetup); + /* Place your code here*/ + }); + + afterEach(async function(this: Context) { + if (!this.currentTest?.isPending()) { + await recorder.stop(); + } + }); + + it("download", async function(this: Context) { + if (!isPlaybackMode()) { + // tslint:disable-next-line:no-invalid-this + this.skip(); + } + + const downloadResponse = await callingServerServiceClient.download(uri); + const metadata = await bodyToString(downloadResponse, downloadResponse.contentLength!); + assert.strictEqual(metadata.includes("0-eus-d15-af5689148b0afa252a57a0121b744dcd"), true); + }); + + it("download with redirection", async function(this: Context) { + if (!isPlaybackMode()) { + // tslint:disable-next-line:no-invalid-this + this.skip(); + } + const redirectedUri = + "https://endpoint/v1/objects/0-sa-d4-a29f0c0212c0a2a634ab078245184de8/content/acsmetadata"; + const downloadResponse = await callingServerServiceClient.download(redirectedUri); + const metadataStream = downloadResponse.readableStreamBody; + assert.notStrictEqual(metadataStream, null); + const metadata = await bodyToString(downloadResponse, downloadResponse.contentLength!); + assert.strictEqual(metadata.includes("0-sa-d4-a29f0c0212c0a2a634ab078245184de8"), true); + }); + + it("unauthorized download", async function(this: Context) { + if (!isPlaybackMode()) { + // tslint:disable-next-line:no-invalid-this + this.skip(); + } + + try { + await callingServerServiceClient.download(uri); + } catch (e) { + assert.equal((e as RestError).statusCode, 401); + } + }); +}); diff --git a/sdk/communication/communication-calling-server/test/public/serverCall.spec.ts b/sdk/communication/communication-calling-server/test/public/serverCall.spec.ts new file mode 100644 index 000000000000..80eb5e94fe4d --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/serverCall.spec.ts @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { env, record, Recorder, RecorderEnvironmentSetup } from "@azure-tools/test-recorder"; +import { CallingServerClient, GroupCallLocator } from "../../src"; +import { CALLBACK_URI } from "./utils/constants"; +import { TestUtils } from "./utils/testUtils"; +import assert from "assert"; +import { Context } from "mocha"; + +const replaceableVariables: { [k: string]: string } = { + COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING: "endpoint=https://endpoint/;accesskey=banana" +}; + +const environmentSetup: RecorderEnvironmentSetup = { + replaceableVariables, + customizationsOnRecordings: [ + (recording: string): string => recording.replace(/(https:\/\/)([^/',]*)/, "$1endpoint"), + (recording: string): string => recording.replace("endpoint:443", "endpoint") + ], + queryParametersToSkip: [] +}; + +describe("Server Call Live Test", function() { + describe("Recording Operations", function() { + let recorder: Recorder; + let connectionString: string; + + beforeEach(async function(this: Context) { + recorder = record(this, environmentSetup); + /* Place your code here*/ + connectionString = + env.COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING || + "endpoint=https://endpoint/;accesskey=banana"; + }); + + afterEach(async function(this: Context) { + if (!this.currentTest?.isPending()) { + await recorder.stop(); + } + }); + + it("Run all client recording operations", async function(this: Context) { + this.timeout(0); + const groupId = TestUtils.getGroupId("Run all client recording operations"); + const fromUser = await TestUtils.getUserId("fromUser", connectionString); + const toUser = await TestUtils.getUserId("toUser", connectionString); + let connections = []; + let recordingId = ""; + + const callingServer = new CallingServerClient(connectionString); + + try { + connections = await TestUtils.createCallConnections( + callingServer, + groupId, + fromUser, + toUser + ); + const callLocator: GroupCallLocator = { groupCallId: groupId }; + + const startCallRecordingResult = await callingServer.startRecording( + callLocator, + CALLBACK_URI + ); + recordingId = startCallRecordingResult.recordingId!; + await TestUtils.delayIfLive(); + let recordingState = await callingServer.getRecordingProperties(recordingId!); + assert.strictEqual(recordingState.recordingState, "active"); + + await callingServer.pauseRecording(recordingId!); + await TestUtils.delayIfLive(); + recordingState = await callingServer.getRecordingProperties(recordingId!); + assert.strictEqual(recordingState.recordingState, "inactive"); + + await callingServer.resumeRecording(recordingId!); + await TestUtils.delayIfLive(); + recordingState = await callingServer.getRecordingProperties(recordingId!); + assert.strictEqual(recordingState.recordingState, "active"); + } finally { + if (recordingId !== "") { + try { + await callingServer.stopRecording(recordingId); + } catch (e) { + console.error("Error stopping recording (" + recordingId + "): " + e); + } + } + } + + await TestUtils.cleanCallConnections(connections); + }); + }); +}); diff --git a/sdk/communication/communication-calling-server/test/public/utils/constants.ts b/sdk/communication/communication-calling-server/test/public/utils/constants.ts new file mode 100644 index 000000000000..03f616d77aa1 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/utils/constants.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { base64encode } from "../../../src/utils/base64"; + +export const NAMESPACE_UUID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8"; +export const CALLBACK_URI = "https://endpoint/callback"; +export const App_Base_Url = "https://endpoint"; +export const Audio_File_Name = "sample-message.wav"; +export const Incoming_Request_Secret = "helloworld"; +export const Audio_File_Url = `${App_Base_Url}/audio/${Audio_File_Name}`; +export const App_Callback_Url = `${App_Base_Url}/api/incident/callback?SecretKey=${base64encode( + Incoming_Request_Secret +)}`; diff --git a/sdk/communication/communication-calling-server/test/public/utils/index.browser.ts b/sdk/communication/communication-calling-server/test/public/utils/index.browser.ts new file mode 100644 index 000000000000..cd62e50510b2 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/utils/index.browser.ts @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * Read body from downloading operation methods to string. + * Works in both Node.js and browsers. + * + * @param response - Convenience layer methods response with downloaded body + * @param length - Length of Readable stream, needed for Node.js environment + */ +export async function bodyToString( + response: { + readableStreamBody?: NodeJS.ReadableStream; + blobBody?: Promise; + }, + _length?: number +): Promise { + const blob = await response.blobBody!; + return blobToString(blob); +} + +export async function blobToString(blob: Blob): Promise { + const fileReader = new FileReader(); + return new Promise((resolve, reject) => { + fileReader.onloadend = (ev: any) => { + resolve(ev.target!.result); + }; + fileReader.onerror = reject; + fileReader.readAsText(blob); + }); +} diff --git a/sdk/communication/communication-calling-server/test/public/utils/index.ts b/sdk/communication/communication-calling-server/test/public/utils/index.ts new file mode 100644 index 000000000000..1d7dc3a5a92c --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/utils/index.ts @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * Read body from downloading operation methods to string. + * Works in both Node.js and browsers. + * + * @param response - Convenience layer methods response with downloaded body + * @param length - Length of Readable stream, needed for Node.js environment + */ +export async function bodyToString( + response: { + readableStreamBody?: NodeJS.ReadableStream; + blobBody?: Promise; + }, + length?: number +): Promise { + return new Promise((resolve, reject) => { + response.readableStreamBody!.on("readable", () => { + const chunk = response.readableStreamBody!.read(length); + if (chunk) { + resolve(chunk.toString()); + } + }); + + response.readableStreamBody!.on("error", reject); + response.readableStreamBody!.on("end", () => { + resolve(""); + }); + }); +} diff --git a/sdk/communication/communication-calling-server/test/public/utils/mockHttpClients.ts b/sdk/communication/communication-calling-server/test/public/utils/mockHttpClients.ts new file mode 100644 index 000000000000..08847892c8e4 --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/utils/mockHttpClients.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { HttpClient, WebResourceLike, HttpOperationResponse, HttpHeaders } from "@azure/core-http"; + +export const createMockHttpClient = >( + status: number = 200, + parsedBody?: T +): HttpClient => { + return { + async sendRequest(httpRequest: WebResourceLike): Promise { + return { + status, + headers: new HttpHeaders(), + request: httpRequest, + parsedBody + }; + } + }; +}; + +export const baseHttpClient: HttpClient = createMockHttpClient(); + +export const base202HttpClient: HttpClient = createMockHttpClient(202); diff --git a/sdk/communication/communication-calling-server/test/public/utils/testUtils.ts b/sdk/communication/communication-calling-server/test/public/utils/testUtils.ts new file mode 100644 index 000000000000..ebd4412d2b9b --- /dev/null +++ b/sdk/communication/communication-calling-server/test/public/utils/testUtils.ts @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { env, isLiveMode, isRecordMode } from "@azure-tools/test-recorder"; +import { v4 as uuidv4, v5 as uuidv5 } from "uuid"; +import { CallingServerClient, CallConnection, GroupCallLocator } from "../../../src"; +import { CommunicationIdentityClient } from "@azure/communication-identity"; +import * as Constants from "../utils/constants"; + +export class TestUtils { + private static delay(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + public static async getUserId(userName: string, connectionString: string): Promise { + const communicationIdentityClient = new CommunicationIdentityClient(connectionString); + const tenant_id = + env.COMMUNICATION_LIVETEST_STATIC_RESOURCE_IDENTIFIER || + "016a7064-0581-40b9-be73-6dde64d69d72"; + + if (!isLiveMode()) { + return "8:acs:" + tenant_id + "_" + uuidv5(userName, Constants.NAMESPACE_UUID); + } + + return (await communicationIdentityClient.createUser()).communicationUserId; + } + + public static getGroupId(testName: string): string { + if (isLiveMode()) { + return uuidv4(); + } + return uuidv5(testName, Constants.NAMESPACE_UUID); + } + + public static async createCallConnections( + callingServerClient: CallingServerClient, + groupId: string, + fromUser: string, + toUser: string + ): Promise { + const joinCallOptions = { + callbackUri: Constants.CALLBACK_URI, + requestedMediaTypes: ["audio"], + requestedCallEvents: ["participantsUpdated"] + }; + const callLocator: GroupCallLocator = { groupCallId: groupId }; + const callConnections = []; + callConnections.push( + await callingServerClient.joinCall( + callLocator, + { communicationUserId: fromUser }, + joinCallOptions + ) + ); + callConnections.push( + await callingServerClient.joinCall( + callLocator, + { communicationUserId: toUser }, + joinCallOptions + ) + ); + return callConnections; + } + + public static async delayIfLive(): Promise { + if (isLiveMode() || isRecordMode()) { + await this.delay(10000); + } + } + + public static async cleanCallConnections(callConnections: Array): Promise { + for (const callConnection of callConnections) { + await callConnection.hangUp(); + } + } +} diff --git a/sdk/communication/communication-calling-server/tests.yml b/sdk/communication/communication-calling-server/tests.yml new file mode 100644 index 000000000000..d308cc7eb91e --- /dev/null +++ b/sdk/communication/communication-calling-server/tests.yml @@ -0,0 +1,22 @@ +trigger: none + +stages: + - template: /eng/pipelines/templates/stages/archetype-sdk-tests.yml + parameters: + PackageName: "@azure/communication-calling-server" + ServiceDirectory: communication + MatrixFilters: + - DependencyVersion=^$ + CloudConfig: + Public: + SubscriptionConfigurations: + - $(sub-config-azure-cloud-test-resources) + - $(sub-config-communication-services-cloud-test-resources-common) + - $(sub-config-communication-services-cloud-test-resources-js) + Int: + SubscriptionConfigurations: + - $(sub-config-communication-int-test-resources-common) + - $(sub-config-communication-int-test-resources-js) + MatrixFilters: + - TestType=^(?!browser).* + Clouds: Public,Int diff --git a/sdk/communication/communication-calling-server/tsconfig.json b/sdk/communication/communication-calling-server/tsconfig.json new file mode 100644 index 000000000000..149deb32e114 --- /dev/null +++ b/sdk/communication/communication-calling-server/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../tsconfig.package", + "compilerOptions": { + "outDir": "./dist-esm", + "declarationDir": "./types", + "paths": { + "@azure/communication-calling-server": ["./src/index"] + }, + "lib": ["dom"] + }, + "include": ["src/**/*.ts", "test/**/*.ts", "samples-dev/**/*.ts"] +} diff --git a/sdk/communication/communication-calling-server/tsdoc.json b/sdk/communication/communication-calling-server/tsdoc.json new file mode 100644 index 000000000000..81c5a8a2aa2f --- /dev/null +++ b/sdk/communication/communication-calling-server/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../../tsdoc.json"] +}