بدء استخدام نموذج بطل الاستدعاء
Azure Communication ServicesGroup Calling Hero Sample يوضح كيف يمكن استخدام Communication Services Calling Web SDK لإنشاء تجربة مكالمة مجموعة.
في هذا التشغيل السريع للعينة، نتعلم كيفية عمل العينة قبل تشغيل العينة على جهازك المحلي ثم نشر النموذج إلى Azure باستخدام موارد Azure Communication Services الخاصة بك.
تنزيل التعليمات البرمجية
ابحث عن المشروع لهذا النموذج على GitHub. يمكن العثور على إصدار من العينة يتضمن ميزات حاليا في المعاينة العامة مثل Teams Interop وتسجيل المكالمات في فرع منفصل.
نظرة عامة
يحتوي النموذج على تطبيق من جانب العميل وتطبيق من جانب الخادم. تطبيق من جانب العميل هو تطبيق ويب React/Redux يستخدم واجهة المستخدم Microsoft's Fluent. يرسل هذا التطبيق طلبات إلى تطبيق من جانب الخادم ASP.NET Core والذي يساعد التطبيق من جانب العميل على الاتصال بـ Azure.
وهكذا يبدو النموذج:
عند الضغط على الزر"بدء مكالمة"، يجلب تطبيق الويب الرمز المميز لوصول المستخدم من التطبيق من جانب الخادم. ثم يتم استخدام هذا الرمز المميز لتوصيل العميل إلى Azure Communication Services. بمجرد استرداد الرمز المميز، تتم مطالبتك بتحديد الكاميرا والميكروفون الذي تريد استخدامه. يمكنك تعطيل/تمكين أجهزتك باستخدام عناصر تحكم التبديل:
بمجرد تكوين اسم العرض والأجهزة، يمكنك الانضمام إلى مدة المكالمة. سترى لوحة الاتصال الرئيسية حيث تعيش تجربة الاتصال الأساسية.
مكونات شاشة المكالمة الرئيسية:
- معرض الوسائط: المرحلة الرئيسية التي يظهر فيها المشاركون. إذا تم تمكين الكاميرا الخاصة بالمشارك، يتم عرض ملف الفيديو الخاص به هنا. لكل مشارك لوحة فردية تعرض اسم العرض وبث الفيديو (عندما يكون هناك واحد)
- العنوان: هذا هو المكان الذي توجد به عناصر التحكم في المكالمة الأساسية للتبديل بين الإعدادات وشريط جانب المشاركين، وتشغيل الفيديو ومزج بين تشغيل / إيقاف، ومشاركة الشاشة والانسحاب من المكالمة.
- الشريط الجانبي:هذا هو المكان الذي يتم فيه عرض معلومات المشاركين والإعدادات عند التبديل باستخدام عناصر التحكم الموجودة في العنوان. يمكن رفض المكون باستخدام "X" الموجود في الزاوية اليمنى العليا. يعرض الشريط الجانبي للمشاركين قائمة بالمشاركين وارتباطا لدعوة المزيد من المستخدمين للدردشة. يسمح شريط الإعدادات الجانبي لك بتكوين إعدادات الميكروفون والكاميرا.
أدناه يمكنك العثور على مزيد من المعلومات حول المتطلبات الأساسية والخطوات لإعداد العينة.
المتطلبات الأساسية
- حساب Azure مع اشتراك نشط. لمزيد من التفاصيل، انظر إنشاء حساب مجانًا
- Node.js (12.18.4 وما فوق)
- Visual Studio Code (بنية مستقرة)
- مورد Azure Communication Services. لمعرفة التفاصيل، انظر إنشاء مورد Azure Communication Services. تحتاج إلى تسجيل سلسلة الاتصال الموارد الخاصة بك لهذا التشغيل السريع.
قبل تشغيل العينة لأول مرة
افتح مثيل PowerShell أو Windows Terminal أو Command Prompt أو ما يعادل ذلك، وانتقل إلى الدليل الذي تريد استنساخ النموذج إليه.
git clone https://github.com/Azure-Samples/communication-services-web-calling-hero.git
احصل على
Connection String
من مدخل Microsoft Azure أو باستخدام Azure CLI.az communication list-key --name "<acsResourceName>" --resource-group "<resourceGroup>"
لمزيد من المعلومات حول سلسلة الاتصال، راجع إنشاء موارد اتصالات Azure
بمجرد الحصول على
Connection String
، أضف سلسلة الاتصال إلى ملف samples/Server/appsetting.json. إدخال سلسلة الاتصال في المتغير:ResourceConnectionString
.احصل على
Endpoint string
من مدخل Microsoft Azure أو باستخدام Azure CLI.az communication list-key --name "<acsResourceName>" --resource-group "<resourceGroup>"
لمزيد من المعلومات حول سلاسل نقطة النهاية، راجع إنشاء موارد اتصالات Azure
بمجرد الحصول على
Endpoint String
، أضف سلسلة نقطة النهاية إلى ملف samples/Server/appsetting.json . إدخال سلسلة نقطة النهاية في المتغيرEndpointUrl
تشغيل محلي
تثبيت التبعيات
npm run setup
بدء تشغيل تطبيق الاتصال
npm run start
يؤدي ذلك إلى فتح خادم عميل على المنفذ 3000 الذي يخدم ملفات موقع الويب، وخادم واجهة برمجة التطبيقات على المنفذ 8080 الذي يؤدي وظائف مثل الرموز المميزة للتصغير للمشاركين في المكالمات.
استكشاف الأخطاء وإصلاحها
يعرض التطبيق شاشة "مستعرض غير مدعوم" لكنني على مستعرض مدعوم.
إذا تم تقديم تطبيقك عبر اسم مضيف آخر غير localhost، فيجب عليك خدمة نسبة استخدام الشبكة عبر https وليس http.
نشر إلى Azure
npm run setup
npm run build
npm run package
- استخدم ملحق Azure وانشر دليل Calling/dist في خدمة التطبيق
تنظيف الموارد
إذا كنت ترغب في تنظيف وإزالة اشتراك Communication Services، يمكنك حذف المورد أو مجموعة الموارد. يؤدي حذف مجموعة الموارد إلى حذف أية موارد أخرى مقترنة بها أيضًا. تعرّف على المزيد حول تنظيف الموارد.
الخطوات التالية
لمزيد من المعلومات، راجع المقالات التالية:
- التعرف على استخدام Calling SDK
- تعرّف على المزيد عن كيفية إجراء المكالمات
لقراءة إضافية
- النماذج - تعرف على المزيد من النماذج والأمثلة على صفحة نظرة عامة على النماذج.
- Redux - إدارة الحالة من جانب العميل
- FluentUI - مكتبة واجهة مستخدم مدعومة من Microsoft
- React - مكتبة لبناء واجهات المستخدم
- ASP.NET Core - إطار عمل لبناء تطبيقات الويب
يوضح نموذج Azure Communication Services Group Calling Hero لنظام التشغيل iOS كيفية استخدام Communication Services Calling iOS SDK لإنشاء تجربة مكالمات جماعية تتضمن الصوت والفيديو. في هذه البداية السريعة عينة، سوف تتعلم كيفية إعداد وتشغيل العينة. يتم توفير نظرة عامة على العينة للسياق.
تنزيل التعليمات البرمجية
ابحث عن المشروع لهذا النموذج على GitHub.
نظرة عامة
النموذج هو تطبيق iOS أصلي يستخدم Azure Communication Services iOS SDKs لإنشاء تجربة مكالمة تتميز بمكالمة صوتية وفيديو. يستخدم التطبيق مكونًا من جانب الملقم لتوفير رموز الوصول المميزة التي يتم استخدامها بعد ذلك لبدء SDK خدمات الاتصالات Azure. لتكوين هذا المكون من جانب الخادم، لا تتردد في اتباع البرنامج التعليمي Trusted Service with Azure Functions .
وهكذا يبدو النموذج:
عند الضغط على الزر "بدء مكالمة جديدة"، يطالبك تطبيق iOS بإدخال اسم العرض لاستخدامه في المكالمة.
بعد الضغط على "التالي" على شاشة "بدء المكالمة"، ستتوفر لك الفرصة لمشاركة معرف المجموعة للمكالمة عبر ورقة مشاركة iOS.
يسمح لك التطبيق أيضا بالانضمام إلى مكالمة Azure Communication Services موجودة عن طريق تحديد معرف المكالمة الحالية أو ارتباط معرف الفرق.
بعد الانضمام إلى مكالمة، ستتم مطالبتك بمنح التطبيق الإذن للوصول إلى الكاميرا والميكروفون، إن لم يكن مصرحا به بالفعل. ضع في اعتبارك أن وظائف الصوت والفيديو الحقيقية متوفرة فقط على الأجهزة الحقيقية، مثل جميع التطبيقات المستندة إلى AVFoundation.
بمجرد تكوين اسم العرض والانضمام إلى المكالمة، سترى لوحة الاتصال الرئيسية حيث توجد تجربة الاتصال الأساسية.
مكونات شاشة المكالمة الرئيسية:
- معرض الوسائط: المرحلة الرئيسية التي يظهر فيها المشاركون. إذا تم تمكين الكاميرا الخاصة بالمشارك، يتم عرض ملف الفيديو الخاص به هنا. يحتوي كل مشارك على تجانب منفرد يظهر اسم العرض وتدفق الفيديو (عندما يكون هناك واحد). يدعم المعرض مشاركين متعددين ويتم تحديثه عند إضافة المشاركين أو إزالتهم إلى المكالمة.
- شريط الإجراءات: هذا هو المكان الذي توجد فيه عناصر التحكم في المكالمات الأساسية. تتيح لك عناصر التحكم هذه تشغيل/إيقاف تشغيل الفيديو والميكروفون ومشاركة شاشتك وترك المكالمة.
وستجد أدناه المزيد من المعلومات حول المتطلبات الأساسية والخطوات لإعداد النموذج.
المتطلبات الأساسية
- حساب Azure مع اشتراك نشط. لمزيد من التفاصيل، راجع إنشاء حساب مجانًا.
- جهاز Mac يعمل بنظام تشغيل Xcode، بالإضافة إلى شهادة مطور صالحة مثبتة على Keychain لديك.
- مورد Azure Communication Services. لمعرفة التفاصيل، انظر إنشاء مورد Azure Communication Services.
- تعمل وظيفة Azure على تشغيل نقطة نهاية المصادقة لجلب رموز الوصول المميزة.
تشغيل نموذج محليًا
يمكن تشغيل نموذج مكالمة المجموعة محليًا باستخدام XCode. يمكن للمطورين إما استخدام الجهاز الفعلي أو المحاكي لاختبار التطبيق.
قبل تشغيل العينة لأول مرة
- تثبيت التبعيات عن طريق تشغيل
pod install
. - افتح
AzureCalling.xcworkspace
في XCode. - إنشاء ملف نصي في الجذر، يسمى
AppSettings.xcconfig
وتعيين القيمة:communicationTokenFetchUrl = <your authentication endpoint, without the https:// component>
قم بتشغيل النموذج
قم بإنشاء وتشغيل العينة في XCode، باستخدام هدف AzureCalling على جهاز المحاكاة أو الجهاز الذي تختاره.
(اختياري) تأمين نقطة نهاية مصادقة
لأغراض العرض التوضيحي، يستخدم هذا النموذج نقطة نهاية يمكن الوصول إليها بشكل عام بشكل افتراضي لجلب رمز وصول Azure Communication Services. بالنسبة إلى سيناريوهات الإنتاج، نوصي باستخدام نقطة النهاية الآمنة الخاصة بك لتوفير الرموز المميزة الخاصة بك.
مع تكوين إضافي، يدعم هذا النموذج الاتصال بنقطة نهاية محمية لمعرف Microsoft Entra (معرف Microsoft Entra) بحيث يكون تسجيل دخول المستخدم مطلوبا للتطبيق لجلب رمز مميز للوصول إلى Azure Communication Services. انظر الخطوات أدناه:
- تمكين مصادقة Microsoft Entra في تطبيقك.
- انتقل إلى صفحة نظرة عامة على التطبيق المسجل ضمن Microsoft Entra App Registrations. دون ملاحظة عن
Application (client) ID
،Directory (tenant) ID
Application ID URI
- أنشئ ملفا
AppSettings.xcconfig
في الجذر إذا لم يكن موجودا بالفعل وأضف القيم:communicationTokenFetchUrl = <Application ID URI, without the https:// component> aadClientId = <Application (client) ID> aadTenantId = <Directory (tenant) ID>
تنظيف الموارد
إذا كنت ترغب في تنظيف وإزالة اشتراك Communication Services، يمكنك حذف المورد أو مجموعة الموارد. يؤدي حذف مجموعة الموارد إلى حذف أية موارد أخرى مقترنة بها أيضًا. تعرّف على المزيد حول تنظيف الموارد.
الخطوات التالية
لمزيد من المعلومات، راجع المقالات التالية:
- التعرف على استخدام Calling SDK
- تعرّف على المزيد عن كيفية إجراء المكالمات
لقراءة إضافية
- Azure Communication GitHub - البحث عن المزيد من الأمثلة والمعلومات على صفحة GitHub الرسمية
- النماذج - تعرف على المزيد من النماذج والأمثلة على صفحة نظرة عامة على النماذج.
- ميزات Azure Communication Calling - لمعرفة المزيد حول استدعاء iOS sdk -Azure Communication iOS Calling SDK
يوضح نموذج Azure Communication Services Group Calling Hero لنظام Android كيف يمكن استخدام Communication Services Calling Android SDK لإنشاء تجربة اتصال جماعية تتضمن الصوت والفيديو. في هذه البداية السريعة عينة، سوف تتعلم كيفية إعداد وتشغيل العينة. يتم توفير نظرة عامة على العينة للسياق.
تنزيل التعليمات البرمجية
ابحث عن المشروع لهذا النموذج على GitHub.
نظرة عامة
العينة هي تطبيق Android أصلي يستخدم مكتبة عميل واجهة مستخدم Azure Communication Services Android لإنشاء تجربة اتصال تتميز بكل من مكالمات الصوت والفيديو. يستخدم التطبيق مكونًا من جانب الملقم لتوفير رموز الوصول المميزة التي يتم استخدامها بعد ذلك لبدء SDK خدمات الاتصالات Azure. لتكوين هذا المكون من جانب الخادم، لا تتردد في اتباع البرنامج التعليمي Trusted Service with Azure Functions .
وهكذا يبدو النموذج:
عند الضغط على الزر "بدء مكالمة جديدة"، يطالبك تطبيق Android بإدخال اسم العرض لاستخدامه في المكالمة.
بعد الضغط على "التالي" في صفحة "بدء مكالمة"، ستتوفر لديك الفرصة لمشاركة "معرف مكالمة المجموعة".
يسمح لك التطبيق بالانضمام إلى مكالمة Azure Communication Services موجودة عن طريق تحديد معرف المكالمة الحالية أو ارتباط معرف اجتماع الفرق واسم العرض.
بعد الانضمام إلى مكالمة، ستتم مطالبتك بمنح التطبيق الإذن للوصول إلى الكاميرا والميكروفون، إن لم يكن مصرحا به بالفعل. سترى لوحة الاتصال الرئيسية حيث تعيش تجربة الاتصال.
مكونات شاشة المكالمة الرئيسية:
- معرض الوسائط: المرحلة الرئيسية التي يظهر فيها المشاركون. إذا تم تمكين الكاميرا الخاصة بالمشارك، يتم عرض ملف الفيديو الخاص به هنا. يحتوي كل مشارك على تجانب منفرد يظهر اسم العرض وتدفق الفيديو (عندما يكون هناك واحد). يدعم المعرض مشاركين متعددين ويتم تحديثه عند إضافة المشاركين أو إزالتهم إلى المكالمة.
- شريط الإجراءات: هذا هو المكان الذي توجد فيه عناصر التحكم في المكالمات الأساسية. تتيح لك عناصر التحكم هذه تشغيل/إيقاف تشغيل الفيديو والميكروفون ومشاركة شاشتك وترك المكالمة.
وستجد أدناه المزيد من المعلومات حول المتطلبات الأساسية والخطوات لإعداد النموذج.
المتطلبات الأساسية
- حساب Azure مع اشتراك نشط. لمزيد من التفاصيل، راجع إنشاء حساب مجانًا.
- Android Studio يعمل على جهاز الكمبيوتر الخاص بك
- مورد Azure Communication Services. لمعرفة التفاصيل، انظر إنشاء مورد Azure Communication Services.
- تعمل وظيفة Azure على تشغيل نقطة نهاية المصادقة لجلب رموز الوصول المميزة.
تشغيل نموذج محليًا
يمكن تشغيل عينة استدعاء المجموعة محليًا باستخدام Android Studio. يمكن للمطورين إما استخدام الجهاز الفعلي أو المحاكي لاختبار التطبيق.
قبل تشغيل العينة لأول مرة
- افتح Android Studio وحدد
Open an Existing Project
- افتح
AzureCalling
المجلد داخل الإصدار الذي تم تنزيله للعينة. - قم بتوسيع التطبيق/الأصول لتحديث
appSettings.properties
. قم بتعيين قيمة المفتاحcommunicationTokenFetchUrl
ليكون عنوان URL لنقطة نهاية المصادقة التي تم إعدادها كشرط أساسي.
قم بتشغيل النموذج
قم ببناء وتشغيل العينة في Android Studio.
(اختياري) تأمين نقطة نهاية مصادقة
لأغراض العرض التوضيحي، يستخدم هذا النموذج نقطة نهاية يمكن الوصول إليها بشكل عام بشكل افتراضي لجلب رمز لـ Azure Communication Services. بالنسبة إلى سيناريوهات الإنتاج، نوصي باستخدام نقطة النهاية الآمنة الخاصة بك لتوفير الرموز المميزة الخاصة بك.
مع تكوين إضافي، يدعم هذا النموذج الاتصال بنقطة نهاية محمية لمعرف Microsoft Entra (معرف Microsoft Entra) بحيث يكون تسجيل دخول المستخدم مطلوبا للتطبيق لجلب رمز Azure Communication Services المميز. انظر الخطوات أدناه:
تمكين مصادقة Microsoft Entra في تطبيقك.
انتقل إلى صفحة نظرة عامة على التطبيق المسجل ضمن Microsoft Entra App Registrations. دون ،
Package name
،Signature hash
MSAL Configutaion
.
تحرير
AzureCalling/app/src/main/res/raw/auth_config_single_account.json
وتعيينisAADAuthEnabled
لتمكين معرف Microsoft Entra.تحرير
AndroidManifest.xml
وتعيينandroid:path
إلى تجزئة توقيع مخزن المفاتيح. (اختياري. تستخدم القيمة الحالية التجزئة من debug.keystore المجمع. إذا تم استخدام مخزن مفاتيح مختلف، يجب تحديث هذا.)<activity android:name="com.microsoft.identity.client.BrowserTabActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="com.azure.samples.communication.calling" android:path="/Signature hash" <!-- do not remove /. The current hash in AndroidManifest.xml is for debug.keystore. --> android:scheme="msauth" /> </intent-filter> </activity>
انسخ تكوين MSAL Android من مدخل Microsoft Azure والصق إلى
AzureCalling/app/src/main/res/raw/auth_config_single_account.json
. تضمين "account_mode": "SINGLE"{ "client_id": "", "authorization_user_agent": "DEFAULT", "redirect_uri": "", "account_mode" : "SINGLE", "authorities": [ { "type": "AAD", "audience": { "type": "AzureADMyOrg", "tenant_id": "" } } ] }
قم بتحرير
AzureCalling/app/src/main/res/raw/auth_config_single_account.json
وتعيين قيمة المفتاحcommunicationTokenFetchUrl
ليكون عنوان URL لنقطة نهاية المصادقة الآمنة.تحرير
AzureCalling/app/src/main/res/raw/auth_config_single_account.json
وتعيين قيمة المفتاحaadScopes
منAzure Active Directory
Expose an API
النطاقاتتعيين قيمة ل
graphURL
فيAzureCalling/app/assets/appSettings.properties
كنقطة نهاية Graph API لجلب معلومات المستخدم.قم بتحرير
AzureCalling/app/src/main/assets/appSettings.properties
وتعيين قيمة المفتاحtenant
لتمكين تسجيل الدخول الصامت بحيث لا يتعين مصادقة المستخدم مرارا وتكرارا أثناء إعادة تشغيل التطبيق.
تنظيف الموارد
إذا كنت ترغب في تنظيف وإزالة اشتراك Communication Services، يمكنك حذف المورد أو مجموعة الموارد. يؤدي حذف مجموعة الموارد إلى حذف أية موارد أخرى مقترنة بها أيضًا. تعرّف على المزيد حول تنظيف الموارد.
الخطوات التالية
لمزيد من المعلومات، راجع المقالات التالية:
- التعرف على استخدام Calling SDK
- تعرّف على المزيد عن كيفية إجراء المكالمات
لقراءة إضافية
- Azure Communication GitHub - البحث عن المزيد من الأمثلة والمعلومات على صفحة GitHub الرسمية
- النماذج - تعرف على المزيد من النماذج والأمثلة على صفحة نظرة عامة على النماذج.
- ميزات Azure Communication Calling - لمعرفة المزيد حول استدعاء Android sdk -Azure Communication Android Calling SDK
يوضح نموذج Azure Communication Services Group Calling Hero لنظام التشغيل Windows كيف يمكن استخدام Communication Services Calling Windows SDK لإنشاء تجربة مكالمات جماعية تتضمن الصوت والفيديو. في هذه العينة، ستتعلم كيفية إعداد العينة وتشغيلها. يتم توفير نظرة عامة على العينة للسياق.
في هذا التشغيل السريع، ستتعلم كيفية بدء مكالمة فيديو 1:1 باستخدام Azure Communication Services Calling SDK لنظام التشغيل Windows.
نموذج التعليمات البرمجية للنظام UWP
المتطلبات الأساسية
لإكمال هذا البرنامج التعليمي، تحتاج إلى المتطلبات الأساسية التالية:
حساب Azure مع اشتراك نشط. أنشئ حساباً مجاناً.
تثبيت Visual Studio 2022 مع حمل عمل تطوير النظام الأساسي العام لـ Windows.
تم نشر مورد Communication Services. إنشاء مورد Communication Services تحتاج إلى تسجيل سلسلة الاتصال الخاص بك لهذا التشغيل السريع.
الرمز المميز لوصول المستخدم لـ Azure Communication Service لديك. يمكنك أيضا استخدام Azure CLI وتشغيل الأمر مع سلسلة الاتصال لإنشاء مستخدم ورمز مميز للوصول.
az communication identity token issue --scope voip --connection-string "yourConnectionString"
للحصول على التفاصيل، راجع استخدام Azure CLI لإنشاء الرموز المميزة للوصول وإدارتها.
الإعداد
إنشاء المشروع
في Visual Studio، قم بإنشاء مشروع جديد باستخدام قالب تطبيق فارغ (Windows عام) لإعداد تطبيق النظام الأساسي العام لـ Windows من صفحة واحدة.
تثبيت الحزمة
انقر بزر الماوس الأيمن فوق المشروع وانتقل إلى Manage Nuget Packages
لتثبيت Azure.Communication.Calling.WindowsClient
الإصدار 1.2.0-beta.1 أو إصدار فائق. تأكد من تحديد Include Preleased.
طلب الإذن بالوصول
انتقل إلى Package.appxmanifest
وانقر فوق Capabilities
.
تحقق من Internet (Client & Server)
للحصول على وصول إلى الإنترنت صادر ووارد.
تحقق من Microphone
للوصول إلى بيانات الصوت الواردة من الميكروفون.
تحقق من WebCam
للوصول إلى كاميرا الجهاز.
أضف التعليمات البرمجية التالية إلى الزر الأيمن بالنقر فوق رمز Package.appxmanifest
العرض واختياره.
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>RtmMvrUap.dll</Path>
<ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
إعداد إطار عمل التطبيق
نحن بحاجة إلى تكوين تخطيط أساسي لإرفاق منطقنا. من أجل إجراء مكالمة صادرة، نحتاج إلى TextBox
توفير معرف المستخدم للمتصل. نحتاج أيضًا إلى زر Start Call
وزر Hang Up
.
نحتاج أيضًا إلى معاينة الفيديو المحلي وعرض الفيديو عن بُعد للمشارك الآخر. لذلك نحن بحاجة إلى عنصرين لعرض تيارات الفيديو.
افتح MainPage.xaml
، واستبدل المحتوى بالتنفيذ التالي:
<Page
x:Class="CallingQuickstart.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CallingQuickstart"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="MainGrid" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="200*"/>
<RowDefinition Height="60*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" x:Name="AppTitleBar" Background="LightSeaGreen">
<!-- Width of the padding columns is set in LayoutMetricsChanged handler. -->
<!-- Using padding columns instead of Margin ensures that the background paints the area under the caption control buttons (for transparent buttons). -->
<TextBlock x:Name="QuickstartTitle" Text="Calling Quickstart sample title bar" Style="{StaticResource CaptionTextBlockStyle}" Padding="4,4,0,0"/>
</Grid>
<TextBox Grid.Row="1" x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" />
<Grid Grid.Row="2" Background="LightGray">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<MediaPlayerElement x:Name="LocalVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="0" VerticalAlignment="Center" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="1" VerticalAlignment="Center" AutoPlay="True" />
</Grid>
<StackPanel Grid.Row="3" Orientation="Vertical" Grid.RowSpan="2">
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock VerticalAlignment="Center">Cameras:</TextBlock>
<ComboBox x:Name="CameraList" HorizontalAlignment="Left" Grid.Column="0" DisplayMemberPath="Name" SelectionChanged="CameraList_SelectionChanged" Margin="10"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="CallButton" Content="Start/Join call" Click="CallButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
<Button x:Name="HangupButton" Content="Hang up" Click="HangupButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
<CheckBox x:Name="MuteLocal" Content="Mute" Margin="10,0,0,0" Click="MuteLocal_Click" Width="74"/>
<CheckBox x:Name="BackgroundBlur" Content="Background blur" Width="142" Margin="10,0,0,0" Click="BackgroundBlur_Click"/>
</StackPanel>
</StackPanel>
<TextBox Grid.Row="4" x:Name="Stats" Text="" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="0,2,0,0" BorderThickness="2" IsReadOnly="True" Foreground="LightSlateGray" />
</Grid>
</Page>
افتح App.xaml.cs
(انقر بزر الماوس الأيمن واختر عرض التعليمات البرمجية) وأضف هذا السطر إلى الأعلى:
using CallingQuickstart;
افتح MainPage.xaml.cs
(انقر بزر الماوس الأيمن واختر عرض الرمز) واستبدل المحتوى بالتنفيذ التالي:
using Azure.Communication.Calling.WindowsClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Media.Core;
using Windows.Networking.PushNotifications;
using Windows.UI;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace CallingQuickstart
{
public sealed partial class MainPage : Page
{
private const string authToken = "<Azure Communication Services auth token>";
private CallClient callClient;
private CallTokenRefreshOptions callTokenRefreshOptions;
private CallAgent callAgent;
private CommunicationCall call = null;
private LocalOutgoingAudioStream micStream;
private LocalOutgoingVideoStream cameraStream;
#region Page initialization
public MainPage()
{
this.InitializeComponent();
// Hide default title bar.
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;
QuickstartTitle.Text = $"{Package.Current.DisplayName} - Ready";
Window.Current.SetTitleBar(AppTitleBar);
CallButton.IsEnabled = true;
HangupButton.IsEnabled = !CallButton.IsEnabled;
MuteLocal.IsChecked = MuteLocal.IsEnabled = !CallButton.IsEnabled;
ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(800, 600);
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
await InitCallAgentAndDeviceManagerAsync();
base.OnNavigatedTo(e);
}
#endregion
private async Task InitCallAgentAndDeviceManagerAsync()
{
// Initialize call agent and Device Manager
}
private async void Agent_OnIncomingCallAsync(object sender, IncomingCall incomingCall)
{
// Accept an incoming call
}
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
// Start a call with video
}
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
// End the current call
}
private async void Call_OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
{
var call = sender as CommunicationCall;
if (call != null)
{
var state = call.State;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
QuickstartTitle.Text = $"{Package.Current.DisplayName} - {state.ToString()}";
Window.Current.SetTitleBar(AppTitleBar);
HangupButton.IsEnabled = state == CallState.Connected || state == CallState.Ringing;
CallButton.IsEnabled = !HangupButton.IsEnabled;
MuteLocal.IsEnabled = !CallButton.IsEnabled;
});
switch (state)
{
case CallState.Connected:
{
break;
}
case CallState.Disconnected:
{
break;
}
default: break;
}
}
}
private async void CameraList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Handle camera selection
}
}
}
نموذج الكائن
تتعامل الفئات والواجهات التالية مع بعض الميزات الرئيسية لـAzure Communication Services Calling SDK:
Name | الوصف |
---|---|
CallClient |
CallClient هو نقطة الإدخال الرئيسية إلى مكتبة عميل الاتصال. |
CallAgent |
CallAgent يتم استخدام لبدء المكالمات والانضمام إليها. |
CommunicationCall |
CommunicationCall يتم استخدام لإدارة المكالمات الموضوعة أو المنضمة. |
CallTokenCredential |
CallTokenCredential يتم استخدام كبيانات اعتماد الرمز المميز لإنشاء مثيل .CallAgent |
CommunicationUserIdentifier |
CommunicationUserIdentifier يتم استخدام لتمثيل هوية المستخدم، والتي يمكن أن تكون أحد الخيارات التالية: CommunicationUserIdentifier أو PhoneNumberIdentifier .CallingApplication |
مصادقة العميل
لتهيئة CallAgent
، تحتاج إلى رمز مميز لوصول المستخدم. بشكل عام يتم إنشاء هذا الرمز المميز من خدمة مع مصادقة خاصة بالتطبيق. لمزيد من المعلومات حول الرموز المميزة لوصول المستخدم، تحقق من دليل الرموز المميزة لوصول المستخدم.
لبدء التشغيل السريع، استبدل <AUTHENTICATION_TOKEN>
برمز الوصول المميز لمستخدم تم إنشاؤه لمورد Azure Communication Service.
بمجرد أن يكون لديك رمز مميز، قم بتهيئة CallAgent
مثيل معه، ما يمكننا من إجراء المكالمات وتلقيها. من أجل الوصول إلى الكاميرات على الجهاز، نحتاج أيضا إلى الحصول على مثيل إدارة الأجهزة.
أضف الرمز التالي إلى دالة InitCallAgentAndDeviceManagerAsync
.
this.callClient = new CallClient(new CallClientOptions() {
Diagnostics = new CallDiagnosticsOptions() {
AppName = "CallingQuickstart",
AppVersion="1.0",
Tags = new[] { "Calling", "ACS", "Windows" }
}
});
// Set up local video stream using the first camera enumerated
var deviceManager = await this.callClient.GetDeviceManagerAsync();
var camera = deviceManager?.Cameras?.FirstOrDefault();
var mic = deviceManager?.Microphones?.FirstOrDefault();
micStream = new LocalOutgoingAudioStream();
CameraList.ItemsSource = deviceManager.Cameras.ToList();
if (camera != null)
{
CameraList.SelectedIndex = 0;
}
callTokenRefreshOptions = new CallTokenRefreshOptions(false);
callTokenRefreshOptions.TokenRefreshRequested += OnTokenRefreshRequestedAsync;
var tokenCredential = new CallTokenCredential(authToken, callTokenRefreshOptions);
var callAgentOptions = new CallAgentOptions()
{
DisplayName = "Contoso",
//https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes/blob/master/all/all.csv
EmergencyCallOptions = new EmergencyCallOptions() { CountryCode = "840" }
};
try
{
this.callAgent = await this.callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);
//await this.callAgent.RegisterForPushNotificationAsync(await this.RegisterWNS());
this.callAgent.CallsUpdated += OnCallsUpdatedAsync;
this.callAgent.IncomingCallReceived += OnIncomingCallAsync;
}
catch(Exception ex)
{
if (ex.HResult == -2147024809)
{
// E_INVALIDARG
// Handle possible invalid token
}
}
بدء مكالمة باستخدام الفيديو
أضف التنفيذ إلى CallButton_Click
لبدء مكالمة باستخدام الفيديو. نحن بحاجة إلى تعداد الكاميرات مع مثيل مدير الجهاز وبناء LocalOutgoingVideoStream
. لبدء مكالمة بالفيديو، نحتاج إلى ضبط VideoOptions
مع LocalVideoStream
وتمريرها مع startCallOptions
لتعيين الخيارات الأولية للمكالمة. من خلال إرفاق LocalOutgoingVideoStream
ب MediaElement
، يمكننا رؤية معاينة الفيديو المحلي.
var callString = CalleeTextBox.Text.Trim();
if (!string.IsNullOrEmpty(callString))
{
if (callString.StartsWith("8:")) // 1:1 Azure Communication Services call
{
call = await StartAcsCallAsync(callString);
}
else if (callString.StartsWith("+")) // 1:1 phone call
{
call = await StartPhoneCallAsync(callString, "+12133947338");
}
else if (Guid.TryParse(callString, out Guid groupId))// Join group call by group guid
{
call = await JoinGroupCallByIdAsync(groupId);
}
else if (Uri.TryCreate(callString, UriKind.Absolute, out Uri teamsMeetinglink)) //Teams meeting link
{
call = await JoinTeamsMeetingByLinkAsync(teamsMeetinglink);
}
}
if (call != null)
{
call.RemoteParticipantsUpdated += OnRemoteParticipantsUpdatedAsync;
call.StateChanged += OnStateChangedAsync;
}
أضف الأساليب لبدء أو الانضمام إلى أنواع مختلفة من المكالمات (مكالمة Azure Communication Services 1:1، مكالمة هاتفية 1:1، مكالمة مجموعة خدمات اتصالات Azure، الانضمام إلى اجتماع Teams، إلخ).
private async Task<CommunicationCall> StartAcsCallAsync(string acsCallee)
{
var options = await GetStartCallOptionsAsynnc();
var call = await this.callAgent.StartCallAsync( new [] { new UserCallIdentifier(acsCallee) }, options);
return call;
}
private async Task<CommunicationCall> StartPhoneCallAsync(string acsCallee, string alternateCallerId)
{
var options = await GetStartCallOptionsAsynnc();
options.AlternateCallerId = new PhoneNumberCallIdentifier(alternateCallerId);
var call = await this.callAgent.StartCallAsync( new [] { new PhoneNumberCallIdentifier(acsCallee) }, options);
return call;
}
private async Task<CommunicationCall> JoinGroupCallByIdAsync(Guid groupId)
{
var joinCallOptions = await GetJoinCallOptionsAsync();
var groupCallLocator = new GroupCallLocator(groupId);
var call = await this.callAgent.JoinAsync(groupCallLocator, joinCallOptions);
return call;
}
private async Task<CommunicationCall> JoinTeamsMeetingByLinkAsync(Uri teamsCallLink)
{
var joinCallOptions = await GetJoinCallOptionsAsync();
var teamsMeetingLinkLocator = new TeamsMeetingLinkLocator(teamsCallLink.AbsoluteUri);
var call = await callAgent.JoinAsync(teamsMeetingLinkLocator, joinCallOptions);
return call;
}
private async Task<StartCallOptions> GetStartCallOptionsAsynnc()
{
return new StartCallOptions() {
OutgoingAudioOptions = new OutgoingAudioOptions() { IsOutgoingAudioMuted = true, OutgoingAudioStream = micStream },
OutgoingVideoOptions = new OutgoingVideoOptions() { OutgoingVideoStreams = new OutgoingVideoStream[] { cameraStream } }
};
}
private async Task<JoinCallOptions> GetJoinCallOptionsAsync()
{
return new JoinCallOptions() {
OutgoingAudioOptions = new OutgoingAudioOptions() { IsOutgoingAudioMuted = true },
OutgoingVideoOptions = new OutgoingVideoOptions() { OutgoingVideoStreams = new OutgoingVideoStream[] { cameraStream } }
};
}
أضف التعليمات البرمجية لإنشاء LocalVideoStream اعتمادا على الكاميرا المحددة على CameraList_SelectionChanged
الأسلوب .
var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamerea);
var localUri = await cameraStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
});
if (call != null)
{
await call?.StartVideoAsync(cameraStream);
}
قبول مكالمة واردة
أضف التنفيذ إلى OnIncomingCallAsync
للرد على مكالمة واردة بالفيديو، ومرر LocalVideoStream
إلى acceptCallOptions
.
var incomingCall = args.IncomingCall;
var acceptCallOptions = new AcceptCallOptions() {
IncomingVideoOptions = new IncomingVideoOptions()
{
IncomingVideoStreamKind = VideoStreamKind.RemoteIncoming
}
};
_ = await incomingCall.AcceptAsync(acceptCallOptions);
مشارك عن بُعد ودفق الفيديو عن بُعد
يتوفر جميع المشاركين عن بُعد من خلال RemoteParticipants
المجموعة في مثيل مكالمة. بمجرد توصيل المكالمة، يمكننا الوصول إلى المشاركين عن بعد في المكالمة والتعامل مع تدفقات الفيديو البعيدة.
private async void Call_OnVideoStreamsUpdatedAsync(object sender, RemoteVideoStreamsEventArgs args)
{
foreach (var remoteVideoStream in args.AddedRemoteVideoStreams)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
RemoteVideo.Source = await remoteVideoStream.Start();
});
}
foreach (var remoteVideoStream in args.RemovedRemoteVideoStreams)
{
remoteVideoStream.Stop();
}
}
private async void Agent_OnCallsUpdatedAsync(object sender, CallsUpdatedEventArgs args)
{
var removedParticipants = new List<RemoteParticipant>();
var addedParticipants = new List<RemoteParticipant>();
foreach(var call in args.RemovedCalls)
{
removedParticipants.AddRange(call.RemoteParticipants.ToList<RemoteParticipant>());
}
foreach (var call in args.AddedCalls)
{
addedParticipants.AddRange(call.RemoteParticipants.ToList<RemoteParticipant>());
}
await OnParticipantChangedAsync(removedParticipants, addedParticipants);
}
private async Task OnParticipantChangedAsync(IEnumerable<RemoteParticipant> removedParticipants, IEnumerable<RemoteParticipant> addedParticipants)
{
foreach (var participant in removedParticipants)
{
foreach(var incomingVideoStream in participant.IncomingVideoStreams)
{
var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
if (remoteVideoStream != null)
{
await remoteVideoStream.StopPreviewAsync();
}
}
participant.VideoStreamStateChanged -= OnVideoStreamStateChanged;
}
foreach (var participant in addedParticipants)
{
participant.VideoStreamStateChanged += OnVideoStreamStateChanged;
}
}
private void OnVideoStreamStateChanged(object sender, VideoStreamStateChangedEventArgs e)
{
CallVideoStream callVideoStream = e.CallVideoStream;
switch (callVideoStream.StreamDirection)
{
case StreamDirection.Outgoing:
OnOutgoingVideoStreamStateChanged(callVideoStream as OutgoingVideoStream);
break;
case StreamDirection.Incoming:
OnIncomingVideoStreamStateChanged(callVideoStream as IncomingVideoStream);
break;
}
}
private async void OnIncomingVideoStreamStateChanged(IncomingVideoStream incomingVideoStream)
{
switch (incomingVideoStream.State)
{
case VideoStreamState.Available:
{
switch (incomingVideoStream.Kind)
{
case VideoStreamKind.RemoteIncoming:
var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
var uri = await remoteVideoStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
RemoteVideo.Source = MediaSource.CreateFromUri(uri);
});
break;
case VideoStreamKind.RawIncoming:
break;
}
break;
}
case VideoStreamState.Started:
break;
case VideoStreamState.Stopping:
break;
case VideoStreamState.Stopped:
if (incomingVideoStream.Kind == VideoStreamKind.RemoteIncoming)
{
var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
await remoteVideoStream.StopPreviewAsync();
}
break;
case VideoStreamState.NotAvailable:
break;
}
}
تقديم ملفات الفيديو عن بعد
لكل دفق فيديو عن بعد، قم بإرفاقه بجهاز MediaElement
.
private async Task AddVideoStreamsAsync(IReadOnlyList<RemoteVideoStream> remoteVideoStreams)
{
foreach (var remoteVideoStream in remoteVideoStreams)
{
var remoteUri = await remoteVideoStream.Start();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
RemoteVideo.Source = remoteUri;
RemoteVideo.Play();
});
}
}
تحديث حالة الاتصال
نحتاج إلى تنظيف أجهزة عرض الفيديو بمجرد قطع الاتصال ومعالجة الحالة عندما ينضم المشاركون عن بعد إلى المكالمة في البداية.
private async void Call_OnStateChanged(object sender, PropertyChangedEventArgs args)
{
switch (((Call)sender).State)
{
case CallState.Disconnected:
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LocalVideo.Source = null;
RemoteVideo.Source = null;
});
break;
case CallState.Connected:
foreach (var remoteParticipant in call.RemoteParticipants)
{
String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
await AddVideoStreams(remoteParticipant.VideoStreams);
remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdated;
}
break;
default:
break;
}
}
إنهاء مكالمة
قم بإنهاء المكالمة الحالية عند النقر فوق الزر Hang Up
. أضف التنفيذ إلى HangupButton_Click لإنهاء مكالمة باستخدام callAgent الذي أنشأناه، وهدم تحديث المشارك ومعالجات أحداث حالة الاتصال.
var call = this.callAgent?.Calls?.FirstOrDefault();
if (call != null)
{
try
{
await call.HangUpAsync(new HangUpOptions() { ForEveryone = true });
}
catch(Exception ex)
{
}
}
تشغيل التعليمات البرمجية
يمكنك إنشاء التعليمات البرمجية وتشغيلها على Visual Studio. بالنسبة إلى الأنظمة الأساسية للحلول، ندعم ARM64
و x64
و x86
.
يمكنك إجراء مكالمة فيديو صادرة عن طريق توفير معرف مستخدم في حقل النص والنقر فوق الزر Start Call
.
ملاحظة: يؤدي الاتصال 8:echo123
إلى إيقاف دفق الفيديو لأن روبوت echo لا يدعم دفق الفيديو.
لمزيدٍ من المعلومات حول معرفات المستخدم (الهوية)، تحقق من دليل رموز الوصول المميزة للمستخدم.
نموذج التعليمات البرمجية ل WinUI 3
المتطلبات الأساسية
لإكمال هذا البرنامج التعليمي، تحتاج إلى المتطلبات الأساسية التالية:
حساب Azure مع اشتراك نشط. أنشئ حساباً مجاناً.
تثبيت Visual Studio 2022 والإصدار SDK لتطبيق Windows 1.2 معاينة 2.
الفهم الأساسي لكيفية إنشاء تطبيق WinUI 3. يعد إنشاء أول مشروع WinUI 3 (SDK لتطبيق Windows) موردا جيدا للبدء به.
تم نشر مورد Communication Services. إنشاء مورد Communication Services تحتاج إلى تسجيل سلسلة الاتصال الخاص بك لهذا التشغيل السريع.
الرمز المميز لوصول المستخدم لـ Azure Communication Service لديك. يمكنك أيضا استخدام Azure CLI وتشغيل الأمر مع سلسلة الاتصال لإنشاء مستخدم ورمز مميز للوصول.
az communication identity token issue --scope voip --connection-string "yourConnectionString"
للحصول على التفاصيل، راجع استخدام Azure CLI لإنشاء الرموز المميزة للوصول وإدارتها.
الإعداد
إنشاء المشروع
في Visual Studio، قم بإنشاء مشروع جديد باستخدام قالب Blank App، Packaged (WinUI 3 في سطح المكتب) لإعداد تطبيق WinUI 3 من صفحة واحدة.
تثبيت الحزمة
انقر بزر الماوس الأيمن فوق المشروع وانتقل إلى Manage Nuget Packages
لتثبيت Azure.Communication.Calling.WindowsClient
الإصدار 1.0.0 أو الإصدار المتفوق. تأكد من تحديد Include Preleased.
طلب الإذن بالوصول
أضف التعليمات البرمجية التالية إلى app.manifest
:
<file name="RtmMvrMf.dll">
<activatableClass name="VideoN.VideoSchemeHandler" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
إعداد إطار عمل التطبيق
نحن بحاجة إلى تكوين تخطيط أساسي لإرفاق منطقنا. من أجل إجراء مكالمة صادرة، نحتاج إلى TextBox
توفير معرف المستخدم للمتصل. نحتاج أيضًا إلى زر Start Call
وزر Hang Up
.
نحتاج أيضًا إلى معاينة الفيديو المحلي وعرض الفيديو عن بُعد للمشارك الآخر. لذلك نحن بحاجة إلى عنصرين لعرض تيارات الفيديو.
افتح MainWindow.xaml
، واستبدل المحتوى بالتنفيذ التالي:
<Page
x:Class="CallingQuickstart.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CallingQuickstart"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="200*"/>
<RowDefinition Height="60*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" x:Name="AppTitleBar" Background="LightSeaGreen">
<!-- Width of the padding columns is set in LayoutMetricsChanged handler. -->
<!-- Using padding columns instead of Margin ensures that the background paints the area under the caption control buttons (for transparent buttons). -->
<TextBlock x:Name="QuickstartTitle" Text="Calling Quickstart sample title bar" Style="{StaticResource CaptionTextBlockStyle}" Padding="4,4,0,0"/>
</Grid>
<TextBox Grid.Row="1" x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" />
<Grid Grid.Row="2" Background="LightGray">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<MediaPlayerElement x:Name="LocalVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="0" VerticalAlignment="Center" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="1" VerticalAlignment="Center" AutoPlay="True" />
</Grid>
<StackPanel Grid.Row="3" Orientation="Vertical" Grid.RowSpan="2">
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock VerticalAlignment="Center">Cameras:</TextBlock>
<ComboBox x:Name="CameraList" HorizontalAlignment="Left" Grid.Column="0" DisplayMemberPath="Name" SelectionChanged="CameraList_SelectionChanged" Margin="10"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="CallButton" Content="Start/Join call" Click="CallButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
<Button x:Name="HangupButton" Content="Hang up" Click="HangupButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
<CheckBox x:Name="MuteLocal" Content="Mute" Margin="10,0,0,0" Click="MuteLocal_Click" Width="74"/>
<CheckBox x:Name="BackgroundBlur" Content="Background blur" Width="142" Margin="10,0,0,0" Click="BackgroundBlur_Click"/>
</StackPanel>
</StackPanel>
<TextBox Grid.Row="4" x:Name="Stats" Text="" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="0,2,0,0" BorderThickness="2" IsReadOnly="True" Foreground="LightSlateGray" />
</Grid>
</Page>
افتح App.xaml.cs
(انقر بزر الماوس الأيمن واختر عرض التعليمات البرمجية) وأضف هذا السطر إلى الأعلى:
using CallingQuickstart;
افتح MainWindow.xaml.cs
(انقر بزر الماوس الأيمن واختر عرض الرمز) واستبدل المحتوى بالتنفيذ التالي:
using Azure.Communication.Calling.WindowsClient;
using Azure.WinRT.Communication;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Media.Core;
namespace CallingQuickstart
{
public sealed partial class MainWindow : Window
{
CallAgent callAgent;
Call call;
DeviceManager deviceManager;
Dictionary<string, RemoteParticipant> remoteParticipantDictionary = new Dictionary<string, RemoteParticipant>();
public MainWindow()
{
this.InitializeComponent();
Task.Run(() => this.InitCallAgentAndDeviceManagerAsync()).Wait();
}
private async Task InitCallAgentAndDeviceManagerAsync()
{
// Initialize call agent and Device Manager
}
private async void Agent_OnIncomingCallAsync(object sender, IncomingCall incomingCall)
{
// Accept an incoming call
}
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
// Start a call with video
}
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
// End the current call
}
private async void Call_OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
{
var state = (sender as Call)?.State;
this.DispatcherQueue.TryEnqueue(() => {
State.Text = state.ToString();
});
}
}
}
نموذج الكائن
تتعامل الفئات والواجهات التالية مع بعض الميزات الرئيسية لـAzure Communication Services Calling SDK:
Name | الوصف |
---|---|
CallClient |
CallClient هو نقطة الإدخال الرئيسية إلى مكتبة عميل الاتصال. |
CallAgent |
CallAgent يتم استخدام لبدء المكالمات والانضمام إليها. |
CommunicationCall |
CommunicationCall يتم استخدام لإدارة المكالمات الموضوعة أو المنضمة. |
CallTokenCredential |
CallTokenCredential يتم استخدام كبيانات اعتماد الرمز المميز لإنشاء مثيل .CallAgent |
CommunicationUserIdentifier |
CommunicationUserIdentifier يتم استخدام لتمثيل هوية المستخدم، والتي يمكن أن تكون أحد الخيارات التالية: CommunicationUserIdentifier أو PhoneNumberIdentifier .CallingApplication |
مصادقة العميل
لتهيئة CallAgent
، تحتاج إلى رمز مميز لوصول المستخدم. بشكل عام يتم إنشاء هذا الرمز المميز من خدمة مع مصادقة خاصة بالتطبيق. لمزيد من المعلومات حول الرموز المميزة لوصول المستخدم، تحقق من دليل الرموز المميزة لوصول المستخدم.
لبدء التشغيل السريع، استبدل <AUTHENTICATION_TOKEN>
برمز الوصول المميز لمستخدم تم إنشاؤه لمورد Azure Communication Service.
بمجرد أن يكون لديك رمز مميز، قم بتهيئة CallAgent
مثيل معه، ما يمكننا من إجراء المكالمات وتلقيها. من أجل الوصول إلى الكاميرات على الجهاز، نحتاج أيضا إلى الحصول على مثيل إدارة الأجهزة.
أضف الرمز التالي إلى دالة InitCallAgentAndDeviceManagerAsync
.
var callClient = new CallClient();
this.deviceManager = await callClient.GetDeviceManagerAsync();
var tokenCredential = new CallTokenCredential("<AUTHENTICATION_TOKEN>");
var callAgentOptions = new CallAgentOptions()
{
DisplayName = "<DISPLAY_NAME>"
};
this.callAgent = await callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);
this.callAgent.OnCallsUpdated += Agent_OnCallsUpdatedAsync;
this.callAgent.OnIncomingCall += Agent_OnIncomingCallAsync;
بدء مكالمة باستخدام الفيديو
أضف التنفيذ إلى CallButton_Click
لبدء مكالمة باستخدام الفيديو. نحن بحاجة إلى تعداد الكاميرات مع مثيل مدير الجهاز وبناء LocalVideoStream
. لبدء مكالمة بالفيديو، نحتاج إلى ضبط VideoOptions
مع LocalVideoStream
وتمريرها مع startCallOptions
لتعيين الخيارات الأولية للمكالمة. من خلال إرفاق LocalVideoStream
ب MediaPlayerElement
، يمكننا رؤية معاينة الفيديو المحلي.
var startCallOptions = new StartCallOptions();
if (this.deviceManager.Cameras?.Count > 0)
{
var videoDeviceInfo = this.deviceManager.Cameras?.FirstOrDefault();
if (videoDeviceInfo != null)
{
var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamerea);
var localUri = await cameraStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
});
startCallOptions.VideoOptions = new OutgoingVideoOptions(new[] { cameraStream });
}
}
var callees = new ICommunicationIdentifier[1]
{
new CommunicationUserIdentifier(CalleeTextBox.Text.Trim())
};
this.call = await this.callAgent.StartCallAsync(callees, startCallOptions);
this.call.OnRemoteParticipantsUpdated += Call_OnRemoteParticipantsUpdatedAsync;
this.call.OnStateChanged += Call_OnStateChangedAsync;
قبول مكالمة واردة
أضف التنفيذ إلى Agent_OnIncomingCallAsync
للرد على مكالمة واردة بالفيديو، ومرر LocalVideoStream
إلى acceptCallOptions
.
var acceptCallOptions = new AcceptCallOptions();
if (this.deviceManager.Cameras?.Count > 0)
{
var videoDeviceInfo = this.deviceManager.Cameras?.FirstOrDefault();
if (videoDeviceInfo != null)
{
var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamerea);
var localUri = await cameraStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
});
acceptCallOptions.VideoOptions = new OutgoingVideoOptions(new[] { localVideoStream });
}
}
call = await incomingCall.AcceptAsync(acceptCallOptions);
مشارك عن بُعد ودفق الفيديو عن بُعد
يتوفر جميع المشاركين عن بُعد من خلال RemoteParticipants
المجموعة في مثيل مكالمة. بمجرد توصيل المكالمة، يمكننا الوصول إلى المشاركين عن بعد في المكالمة والتعامل مع تدفقات الفيديو البعيدة.
private async void Call_OnVideoStreamsUpdatedAsync(object sender, RemoteVideoStreamsEventArgs args)
{
foreach (var remoteVideoStream in args.AddedRemoteVideoStreams)
{
this.DispatcherQueue.TryEnqueue(async () => {
RemoteVideo.Source = MediaSource.CreateFromUri(await remoteVideoStream.Start());
RemoteVideo.MediaPlayer.Play();
});
}
foreach (var remoteVideoStream in args.RemovedRemoteVideoStreams)
{
remoteVideoStream.Stop();
}
}
private async void Agent_OnCallsUpdatedAsync(object sender, CallsUpdatedEventArgs args)
{
foreach (var call in args.AddedCalls)
{
foreach (var remoteParticipant in call.RemoteParticipants)
{
var remoteParticipantMRI = remoteParticipant.Identifier.ToString();
this.remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
await AddVideoStreamsAsync(remoteParticipant.VideoStreams);
remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdatedAsync;
}
}
}
private async void Call_OnRemoteParticipantsUpdatedAsync(object sender, ParticipantsUpdatedEventArgs args)
{
foreach (var remoteParticipant in args.AddedParticipants)
{
String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
this.remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
await AddVideoStreamsAsync(remoteParticipant.VideoStreams);
remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdatedAsync;
}
foreach (var remoteParticipant in args.RemovedParticipants)
{
String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
this.remoteParticipantDictionary.Remove(remoteParticipantMRI);
}
}
تقديم ملفات الفيديو عن بعد
لكل دفق فيديو عن بعد، قم بإرفاقه بجهاز MediaPlayerElement
.
private async Task AddVideoStreamsAsync(IReadOnlyList<RemoteVideoStream> remoteVideoStreams)
{
foreach (var remoteVideoStream in remoteVideoStreams)
{
var remoteUri = await remoteVideoStream.Start();
this.DispatcherQueue.TryEnqueue(() => {
RemoteVideo.Source = MediaSource.CreateFromUri(remoteUri);
RemoteVideo.MediaPlayer.Play();
});
}
}
تحديث حالة الاتصال
نحتاج إلى تنظيف أجهزة عرض الفيديو بمجرد قطع الاتصال ومعالجة الحالة عندما ينضم المشاركون عن بعد إلى المكالمة في البداية.
private async void Call_OnStateChanged(object sender, PropertyChangedEventArgs args)
{
switch (((Call)sender).State)
{
case CallState.Disconnected:
this.DispatcherQueue.TryEnqueue(() => { =>
{
LocalVideo.Source = null;
RemoteVideo.Source = null;
});
break;
case CallState.Connected:
foreach (var remoteParticipant in call.RemoteParticipants)
{
String remoteParticipantMRI = remoteParticipant.Identifier.ToString();
remoteParticipantDictionary.TryAdd(remoteParticipantMRI, remoteParticipant);
await AddVideoStreams(remoteParticipant.VideoStreams);
remoteParticipant.OnVideoStreamsUpdated += Call_OnVideoStreamsUpdated;
}
break;
default:
break;
}
}
إنهاء مكالمة
قم بإنهاء المكالمة الحالية عند النقر فوق الزر Hang Up
. أضف التنفيذ إلى HangupButton_Click لإنهاء مكالمة باستخدام callAgent الذي أنشأناه، وهدم تحديث المشارك ومعالجات أحداث حالة الاتصال.
this.call.OnRemoteParticipantsUpdated -= Call_OnRemoteParticipantsUpdatedAsync;
this.call.OnStateChanged -= Call_OnStateChangedAsync;
await this.call.HangUpAsync(new HangUpOptions());
تشغيل التعليمات البرمجية
يمكنك إنشاء التعليمات البرمجية وتشغيلها على Visual Studio. بالنسبة إلى الأنظمة الأساسية للحلول، ندعم ARM64
و x64
و x86
.
يمكنك إجراء مكالمة فيديو صادرة عن طريق توفير معرف مستخدم في حقل النص والنقر فوق الزر Start Call
.
ملاحظة: يؤدي الاتصال 8:echo123
إلى إيقاف دفق الفيديو لأن روبوت echo لا يدعم دفق الفيديو.
لمزيدٍ من المعلومات حول معرفات المستخدم (الهوية)، تحقق من دليل رموز الوصول المميزة للمستخدم.
الملاحظات
https://aka.ms/ContentUserFeedback.
قريبًا: خلال عام 2024، سنتخلص تدريجيًا من GitHub Issues بوصفها آلية إرسال ملاحظات للمحتوى ونستبدلها بنظام ملاحظات جديد. لمزيد من المعلومات، راجعإرسال الملاحظات وعرضها المتعلقة بـ