{"id":13493837,"url":"https://github.com/100mslive/100ms-ios-sdk","last_synced_at":"2025-04-10T00:18:15.380Z","repository":{"id":38343823,"uuid":"369549830","full_name":"100mslive/100ms-ios-sdk","owner":"100mslive","description":"iOS Video Conferencing SDK \u0026 Sample App","archived":false,"fork":false,"pushed_at":"2025-01-27T08:50:18.000Z","size":41327,"stargazers_count":55,"open_issues_count":3,"forks_count":12,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-10T00:18:01.987Z","etag":null,"topics":["hacktoberfest","ios","sdk","video"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/100mslive.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-21T13:48:00.000Z","updated_at":"2025-04-04T22:44:53.000Z","dependencies_parsed_at":"2023-02-05T23:02:01.534Z","dependency_job_id":"74c1b498-5a99-40fa-ade8-d3a0e4797c1d","html_url":"https://github.com/100mslive/100ms-ios-sdk","commit_stats":{"total_commits":163,"total_committers":7,"mean_commits":"23.285714285714285","dds":0.6012269938650308,"last_synced_commit":"0b6e1c223d5995a3a2510360b7733900b807cebb"},"previous_names":[],"tags_count":98,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/100mslive%2F100ms-ios-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/100mslive%2F100ms-ios-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/100mslive%2F100ms-ios-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/100mslive%2F100ms-ios-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/100mslive","download_url":"https://codeload.github.com/100mslive/100ms-ios-sdk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248131318,"owners_count":21052820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","ios","sdk","video"],"created_at":"2024-07-31T19:01:19.295Z","updated_at":"2025-04-10T00:18:15.357Z","avatar_url":"https://github.com/100mslive.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"\n\u003ca href=\"https://100ms.live/\"\u003e\n\u003cimg src=\"https://github.com/100mslive/100ms-ios-sdk/blob/main/100ms.gif\" height=256/\u003e \n\u003cimg src=\"https://github.com/100mslive/100ms-ios-sdk/blob/main/100ms.svg\" title=\"100ms logo\" float=center height=256\u003e\n\u003c/a\u003e\n\n[![Cocoapods](https://img.shields.io/cocoapods/v/HMSSDK)](https://www.100ms.live/)\n[![iOS](https://img.shields.io/badge/iOS-10.0%2B-yellow)](https://www.100ms.live/)\n[![License](https://img.shields.io/cocoapods/l/HMSSDK.svg?style=flat)](https://www.100ms.live/)\n[![Documentation](https://img.shields.io/badge/Read-Documentation-blue)](https://docs.100ms.live/ios/v2/foundation/Basics)\n[![Discord](https://img.shields.io/discord/843749923060711464?label=Join%20on%20Discord)](https://100ms.live/discord)\n[![TestFlight](https://img.shields.io/badge/Download%20via-TestFlight-blue)](https://testflight.apple.com/join/dhUSE7N8)\n[![Activity](https://img.shields.io/github/commit-activity/m/100mslive/100ms-ios-sdk.svg)](https://github.com/100mslive/100ms-ios-sdk/releases)\n[![Email](https://img.shields.io/badge/Contact-Know%20More-blue)](https://dashboard.100ms.live/register)\n\n## 🎨 Features\n- [x] [RTMP](https://www.100ms.live/docs/ios/v2/features/rtmp-recording)/[HLS](https://www.100ms.live/docs/ios/v2/features/hls) Streaming to multiple destinations\n- [x] [Call Recording](https://www.100ms.live/docs/ios/v2/foundation/recordings)\n- [x] [Virtual Background](https://www.100ms.live/docs/ios/v2/plugins/virtual-background) ([custom video plugins](https://www.100ms.live/docs/ios/v2/plugins/custom-video-plugins) for realtime effects)\n- [x] [Screen Sharing](https://www.100ms.live/docs/ios/v2/features/screen-share)\n- [x] [Local Audio Playback](https://www.100ms.live/docs/ios/v2/features/audio-share)\n- [x] [Picture in picture (PiP)](https://www.100ms.live/docs/ios/v2/features/pip-mode)\n- [x] [Network quality indicator](https://www.100ms.live/docs/ios/v2/features/network-quality-reports)\n\n👀 To see the complete list of features checkout our [documentation overview page](https://www.100ms.live/docs/ios)\n\n# 🎉 100ms SDK ＆ Sample App 🚀\n\nHere you will find everything you need to build experiences with video using 100ms iOS SDK. Dive into our SDKs, quick starts, add real-time video, voice, and screen sharing to your web and mobile applications.\n\n👀 To see a Example App implementation of 100ms SDK, checkout the [ReadMe in Example folder](https://github.com/100mslive/100ms-ios-sdk/tree/main/Example).\n\n📲 Download the 100ms fully featured Sample iOS app here: https://testflight.apple.com/join/dhUSE7N8\n  \n## ☝️ Pre-requisites\n- Xcode 12 or higher\n- Support for iOS 12 or higher\n\n## 🚂 Setup Guide\n  \n  1. Sign up on https://dashboard.100ms.live/register \u0026 visit the Developer tab to access your credentials.\n  \n  2. Get familiarized with [Tokens \u0026 Security here](https://docs.100ms.live/ios/v2/foundation/security-and-tokens)\n\n  3. Complete the steps in [Auth Token Quick Start Guide](https://docs.100ms.live/ios/v2/guides/token)\n  \n  4. Get the HMSSDK via [Cocoapods](https://cocoapods.org/). Add the `pod 'HMSSDK'` to your Podfile as follows:\n  ```ruby\n  # Podfile\n  \n  platform :ios, '12.0'\n\n  target 'MyAwesomeApp' do\n    use_frameworks!\n    pod 'HMSSDK'\n  end\n  ```\n\n  then run `pod install --repo-update`\n\n  You can also use [Swift Package Manager](https://www.100ms.live/docs/ios/v2/features/integration#swift-package-manager) (use https://github.com/100mslive/100ms-ios-sdk.git as the package source)\n  \n  Follow the [iOS Quick Start Guide as mentioned here](https://docs.100ms.live/ios/v2/guides/quickstart).\n  \n## 🧐 Key Concepts\n\n- `Room` - A room represents real-time audio, video session, the basic building block of the 100mslive Video SDK\n- `Track` - A track represents either the audio or video that makes up a stream\n- `Peer` - A peer represents all participants connected to a room. Peers can be \"local\" or \"remote\"\n- `Broadcast` - A local peer can send any message/data to all remote peers in the room \n\n## ♻️ Setup event listeners\n\n100ms SDK provides callbacks to the client app about any change or update happening in the room after a user has joined by implementing `HMSUpdateListener`. These updates can be used to render the video on screen or to display other info regarding the room.\n\n```swift\n@objc public protocol HMSUpdateListener {\n\n    /// This will be called on a successful JOIN of the room by the user\n    /// This is the point where applications can stop showing its loading state\n    /// - Parameter room: the room which was joined\n    @objc(onJoin:) func on(join room: HMSRoom)\n\n    /// This is called when there is a change in any property of the Room\n    /// - Parameters:\n    ///   - room: the room which was joined\n    ///   - update: the triggered update type. Should be used to perform different UI Actions\n    @objc(onRoom:update:) func on(room: HMSRoom, update: HMSRoomUpdate)\n\n    /// This will be called whenever there is an update on an existing peer\n    /// or a new peer got added/existing peer is removed.\n    /// This callback can be used to keep a track of all the peers in the room\n    /// - Parameters:\n    ///   - peer: the peer who joined/left or was updated\n    ///   - update: the triggered update type. Should be used to perform different UI Actions\n    @objc(onPeer:update:) func on(peer: HMSPeer, update: HMSPeerUpdate)\n\n    /// This is called when there are updates on an existing track\n    /// or a new track got added/existing track is removed\n    /// This callback can be used to render the video on screen whenever a track gets added\n    /// - Parameters:\n    ///   - track: the track which was added, removed or updated\n    ///   - update: the triggered update type\n    ///   - peer: the peer for which track was added, removed or updated\n    @objc(onTrack:update:peer:) func on(track: HMSTrack, update: HMSTrackUpdate, for peer: HMSPeer)\n\n    /// This will be called when there is an error in the system\n    /// and SDK has already retried to fix the error\n    /// - Parameter error: the error that occured\n    @objc(onError:) func on(error: HMSError)\n\n    /// This is called when there is a new broadcast message from any other peer in the room\n    /// This can be used to implement chat is the room\n    /// - Parameter message: the received broadcast message\n    @objc(onMessage:) func on(message: HMSMessage)\n\n    /// This is called when a role change request arrives\n    /// - Parameter roleChangeRequest: the request for role change info\n    @objc(roleChangeRequest:) optional func on(roleChangeRequest: HMSRoleChangeRequest)\n\n    /// This is called when a change track state request arrives\n    /// - Parameter changeTrackStateRequest: the request for changing track state\n    @objc(changeTrackStateRequest:) optional func on(changeTrackStateRequest: HMSChangeTrackStateRequest)\n\n    /// This is called when someone removes the local peer for the current room\n    /// - Parameter notification: the notification containing reason for removing and the initiating peer\n    @objc(removedFromRoom:) optional func on(removedFromRoom notification: HMSRemovedFromRoomNotification)\n\n    /// This is called every 1 second with list of active speakers\n    ///\n    ///  A HMSSpeaker object contains -\n    ///    - peer: the peer who is speaking\n    ///    - track: the track which is emitting audio\n    ///    - level: a number within range 1-100 indicating the audio volume\n    ///\n    /// A peer who is not present in the list indicates that the peer is not speaking\n    /// \n    /// This can be used to highlight currently speaking peers in the room\n    /// - Parameter speakers: the list of speakers\n    @objc(onUpdatedSpeakers:) func on(updated speakers: [HMSSpeaker])\n\n    /// This is called when SDK detects a network issue and is trying to recover\n    @objc func onReconnecting()\n\n    /// This is called when SDK successfully recovered from a network issue\n    @objc func onReconnected()\n}\n\n@objc public protocol HMSPreviewListener {\n\n    @objc(onPreview:localTracks:) func onPreview(room: HMSRoom, localTracks: [HMSTrack])\n\n    @objc(onError:) func on(error: HMSError)\n}\n\n@objc public protocol HMSLogger {\n\n    @objc(logMessage:level:) func log(_ message: String, _ level: HMSLogLevel)\n}\n```\n  \n## 🤔 How to listen to Track, Peer and Room updates? \n\n  The HMS SDK sends updates to the application about any change in HMSPeer , HMSTrack or HMSRoom via the callbacks in HMSUpdateListener.\n  Application need to listen to the corresponding updates in onPeerUpdate , onTrackUpdate or onRoomUpdate\n\n  The following are the different types of updates that are emitted by the SDK - \n```swift\n/// Whenever a property of peer changes\n@objc public enum HMSPeerUpdate : Int, CustomStringConvertible {\n\n    /// When a new peer joins the room\n    case peerJoined\n\n    /// When an existing peer leaves the room\n    case peerLeft\n\n    /// When a peer's role has been updated\n    case roleUpdated\n\n    case defaultUpdate\n\n    /// Get a string useful for debugging\n    public var description: String { get }\n}\n\n\n/// Whenever an property of a track changes\n@objc public enum HMSTrackUpdate : Int, CustomStringConvertible {\n\n    /// a new track got added\n    case trackAdded\n\n    /// an existing track was removed\n    case trackRemoved\n\n    /// a track was muted\n    case trackMuted\n\n    /// a muted track was unmuted\n    case trackUnmuted\n\n    /// description of track changed\n    case trackDescriptionChanged\n\n    /// a track got degraded due to bad network\n    case trackDegraded\n\n    /// a track got restored due to improvement in network\n    case trackRestored\n\n    /// a string useful in debuggin\n    public var description: String { get }\n}\n ```\n  \n## 🛤 How to know the type and source of Track?\n\n  HMSTrack contain a field called source which denotes the source of the Track. \n  Source can have the following values - regular (normal), screen (for screenshare)and plugin (for plugins)\n\n  To know the type of track, check the value of type which would be one of the enum values - AUDIO or VIDEO\n  \n## 🤝 Provide joining configuration\n\nTo join a room created by following the steps described in the above section, clients need to create a `HMSConfig` instance and use that instance to call `join` method of `HMSSDK`\n\n```swift\n// Create a new HMSConfig\nlet config = HMSConfig(userName: user, // name of the user\n                         userID: UUID().uuidString, // some unique identifier\n                         roomID: room, // unique ID of the room which user wants to join\n                      authToken: token) // authorisation token of the user\n```\n\n## 🙏 Join a room\n\nUse the HMSConfig and HMSUpdateListener instances to call the join method on the instance of HMSSDK created above.\nOnce Join succeeds, all the callbacks keep coming on every change in the room and the app can react accordingly\n\n```swift\n// Basic Usage\nhms = HMSSDK.build() // ensure to keep an instance of HMSSDK alive in the class as an instance property\nlet config = HMSConfig(userName: \"user name\", authToken: \"auth token\") \nhms?.join(config: config, delegate: self)\n\n\n// Advanced Usage\nhms = HMSSDK.build { (sdk) in\n  sdk.appGroup = \"group.live.100ms.videoapp\"\n    \n  sdk.trackSettings = HMSTrackSettings.build { videoSettingsBuilder, audioSettingsBuilder in\n    videoSettingsBuilder.initialMuteState = .mute\n    videoSettingsBuilder.videoPlugins = self.videoPlugins\n        \n    audioSettingsBuilder.initialMuteState = .mute\n    audioSettingsBuilder.audioSource = self.audioSource(for: sdk)\n  }\n    \n  sdk.logger = self\n}\n\nlet config = HMSConfig(userName: \"user name\",\n                      authToken: \"auth token\",\n                       metaData: \"some metadata\",\n captureNetworkQualityInPreview: true)\n\nhms?.join(config: config, delegate: self)\n\n```\n\n## 👋 Leave Room\n\nCall the leave method on the HMSSDK instance\n\n```swift\nhms?.leave() // to leave a room\n```\n\n## 👌 Get Peers/tracks data\n\n`HMSSDK` has other methods which the client app can use to get more info about the `Room`, `Peer` and `Tracks`\n\n```swift  \n/// Returns the local peer, which contains the local tracks\nvar localPeer: HMSLocalPeer? { get }\n\n\n/// Returns all remote peers in the room\nvar remotePeers: [HMSRemotePeer]? { get }\n\n\n/// Returns the room which was joined\nvar room: HMSRoom? { get }\n```\n  \n## 🙊 Mute/Unmute Local Audio\nUse the `HMSLocalAudioTrack` and `HMSLocalVideoTrack` to mute/unmute tracks\n  \n```swift\nclass HMSLocalAudioTrack : HMSAudioTrack {\n\n  var settings: HMSAudioTrackSettings\n\n  func setMute(_ mute: Bool)\n}\n```\n\n## 🙈 Mute/Unmute Local Video  \n  \n```swift  \nclass HMSLocalVideoTrack : HMSVideoTrack {\n\n  var settings: HMSVideoTrackSettings\n\n  func setMute(_ mute: Bool)\n\n  func startCapturing()\n\n  func stopCapturing()\n\n  func switchCamera()\n}\n```\n  \n## 🛤 HMSTracks Explained\n  \n`HMSTrack` is the super-class of all the tracks that are used inside `HMSSDK`. Its hierarchy looks like this -\n  \n```\nHMSTrack\n    - AudioTrack\n        - LocalAudioTrack\n        - RemoteAudioTrack\n    - VideoTrack\n        - LocalVideoTrack\n        - RemoteVideoTrack\n```\n  \n## 🎞 Display a Track\n  To display a video track, first get the `HMSVideoTrack` \u0026 pass it on to `HMSVideoView` using `setVideoTrack` function. Ensure to attach the `HMSVideoView` to your UI hierarchy.\n\n```swift\n// The following code is a sample.\n\n// get the video track to be displayed\nlet track = peer.videoTrack  \n\n// create a view for rendering video track and add to the UI hierarchy\nlet videoView = HMSVideoView()\n\n// set the video track of HMSVideoView\nvideoView.setVideoTrack(track)\n\n// add the view to UI hierarchy\nview.addSubview(videoView)\n```\n\n## 📨 Chat Messaging\nWhat's a video without being able to send messages to each other too? 100ms supports chat for every video/audio room you create.\n\nYou can see an example of every way of sending messages and interpreting messages in the advanced [sample app](https://github.com/100mslive/100ms-ios-sdk).\n\n### Addressing messages\n\n* [Broadcast messages](#sending-broadcast-messages) can be sent to Everyone in the chat `hmssdk.sendBroadcastMessage`.\n\n* [Direct messages](#sending-direct-messages) let you send message to a specific person `hmssdk.sendDirectMessage`.\n\n* [Group messages](#sending-group-messages) let you send a message to everyone with a particular `HMSRole`. Such as all `hosts` or all `teachers` or all `students` `hmsSdk.sendGroupMessage`\n\n### Sending Chat Messages\n\n#### Sending Broadcast Messages\n\nYou want to let everyone in the chat know something? Call `sendBroadcastMessage` on the instance of `HMSSDK` to a send a broadcast.\n\nThe text of the message, its type and a listener for whther the message reached the server or not are the parameters.\n\n\u003e 💡 Note that the callback only lets you know if the server has received your request for the message or if there was some error. It does not convey whether the message was delivered to or read by the recipient.\n\u003e also it's important to make a new callback per message because it will only contain the results of that particular call for sending a message.\n\n\n```swift\nhmssdk.sendBroadcastMessage(type: \"chat\", message: \"\") { message, error in\n\n}\n```\n\n#### Sending Direct Messages\n\nGot secrets to share? Send a message directly to a single person in the chat with a direct message. Call `sendDirectMessage` on an instance of `HMSSDK`.\n\nThe text of the message, its type and a listener for whther the message reached the server or not are the parameters.\n\n\u003e 💡 Note that the callback only lets you know if the server has received your request for the message or if there was some error. It does not convey whether the message was delivered to or read by the recipient.\n\u003e also it's important to make a new callback per message because it will only contain the results of that particular call for sending a message.\n\n```swift\nhmssdk.sendDirectMessage(type: \"chat\", message: \"\", peer: recipientPeer) { message, error in\n\n}\n```\n\n#### Sending Group Messages\n\nWant to share with a group? Send a message directly to a group in the chat with a group message. Call `sendGroupMessage` on an instance of `HMSSDK`.\n\nThe text of the message, its type and a listener for whether the message reached the server or not are the parameters.\n\n\u003e 💡 Note that the callback only lets you know if the server has received your request for the message or if there was some error. It does not convey whether the message was delivered to or read by the recipient.\n\u003e also it's important to make a new callback per message because it will only contain the results of that particular call for sending a message.\n\n```swift\nhmssdk.sendGroupMessage(type: \"chat\", message: \"\", roles: recipientRoles) { message, error in\n\n}\n```\n\n### Receiving Chat Messages\n\nWhen you called `hmsSdk.join(config, delegate)` to join a room, the `HMSUpdateListener` implementation that was passed in had the callback `on(message:)`.\n\nThis where you'll receive new messages as `HMSMessage` during the call. It contains:\n\n```swift\npublic class HMSMessage {\n    public let message: String\n    public let type: String\n    public var sender: HMSPeer?\n    public var recipient: HMSMessageRecipient\n    public let time: Date\n}\n```\n`message`: Content of the text message or the text description of the raw message.\n\n`type`: Type of message sent. Default value is `chat`.\n\n`recipient`: The intended recipient(s) of this message as a `HMSMessageRecipient`.\n\n`time`: timestamp of when the messaging server receives this message. Update the time in your own messages when this comes back from the server in `on(message:)` for accurate ordering of your own messages.\n\n`sender`: The `HMSPeer` who is sending this message.\n\nIdentifying Senders: The sender of a message is always contained in the `sender` field of HMSMessage. This lets you get the name and peer id for any message sender.\n\nMessage Body: The body of the message is in `message` as a String.\n\nTime: The time the message was sent is contained in `time`.\n\n#### Identifying who the message was for\n\nThe HMSMessageRecipient contained in the `recipient` field of `HMSMessage` lets you know who the message was for.\n\nThe `HMSMessageRecipient` contains:\n```swift\npublic class HMSMessageRecipient {\n    public let type: HMSMessageRecipientType\n    public let peerRecipient: HMSPeer?\n    public let rolesRecipient: [HMSRole]?\n}\n```\n\n`peerRecipient`: Only contains a peer when a specific single peer is being direct messaged.\n\n`rolesRecipient`: Only contains values when a group message is being sent to one or many roles.\n\n`type`: Will be `broadcast` for a message being sent to everyone. If this is true, the other two field will be null, empty respectively.\n\n`peer` will be set when it's a direct message.\n\n`roles` will be set when it's a message to one or many roles. \n\n## 🤳 Preview\n\nPreview screen is a frequently used UX element which allows users to check if their input devices are working properly and set the initial state (mute/unmute) of their audio and video tracks before joining. 100ms SDKs provide an easy-to-use API to back this feature. Additionally, the SDK will try to establish a connection to 100ms server to verify there are no network issues and that the auth credentials are valid so that if everything is in order the subsequent room join is instant.\n\nTo invoke this API call\n\n```swift\nhmsSDK.preview(config: config, delegate: previewDelegate)\n```\n\nYou would need the same config object that you would pass to [join API](Join). The `previewDelegate` is an object conforming to `HMSPreviewListener` protocol that has two callbacks:\n\n```swift\nfunc onPreview(room: HMSRoom, localTracks: [HMSTrack])\n```\n\nWhich is called when SDK has passed all its preflight checks and established the connection to 100ms server. This will pass an array of local tracks that you can display to the user (see [Render Video](Render-Video) and [Mute](Mute) sections for more details).\n\nIf however there was some error related to getting the input sources or some preflight check has failed \n\n```swift\nfunc on(error: HMSError)\n```\n\nDelegate callback will be fired with the HMSError instance which you can use to find what went wrong.\n\n## ⚙️ Change Role\n\nRole is a powerful concept that takes a lot of complexity away in handling permissions and supporting features like breakout rooms. [Learn more about roles here.](../foundation/templates-and-roles)\n\nEach `HMSPeer` instance has a `role` property which returns an `HMSRole` instance. You can use this property to do following:\n\n1. Check what this role is allowed to publish. I.e can it send video (and at what resolution)? can it send audio? can it  share screen? Who can this role subscribe to? (I.e student can only see the teacher's video) This is can be discovered by checking `publishSettings` and `subscribeSettings` properties\n2. Check what actions this role can perform. i.e can it change someone else's current role, end meeting, remove someone from the room. This is can be discovered by checking `permissions` property\n\nIn certain scenarios you may want to change someone's role. Imagine an audio room with 2 roles \"speaker\" and \"listener\". Only someone with a \"speaker\" role can publish audio to the room while \"listener\" can only subscribe. Now at some point \"speaker\" may decide to nominate some \"listener\" to become a \"speaker\". This is where the `changeRole` API comes in.\n\nTo invoke the api you will need 2 things. An instance of `HMSPeer` of the peer who's role you want to change and the `HMSRole` instance for the target role.  All the peers that are in the current room are accessible via `peers` property of `HMSRoom` instance that you can get via `room` property of `HMSSDK` instance after successful room join. A list of all available roles in the current room can be accessed via `roles` property of `HMSSDK` \n\nOnce you have both you can invoke\n\n```swift\n hmsSDK.changeRole(for: targetPeer, role: targetRole)\n```\n\nIf the change role succeeds you will get a \n\n```swift\nfunc on(peer: HMSPeer, update: HMSPeerUpdate)\n```\n\ndelegate callback with the the same peer you passed as targetPeer and a `roleUpdated` update type.\n\n`changeRole` has an optional `force` parameter which is `false` by default meaning that `changeRole` is basically a polite request: \"Would you like to change you role from listener to speaker?\" which can be ignored by the other party. The way it works is the other party will first receive a \n\n```swift\nfunc on(roleChangeRequest: HMSRoleChangeRequest)\n```\n\ndelegate callback. At which point app can choose to show a prompt to the user asking for permission. If the user accepts, app should call \n\n```swift\nhmsSDK.accept(changeRole: roleChangeRequest)\n```\n\nwhich completes the `changeRole` loop. Both parties will receive a `roleUpdated` callback so that they both can do necessary UI updates. Now the user actually becomes a speaker and the audio publishing will start automatically. \n\nNow lets imagine the newly nominated speaker is not behaving nicely and we want to move him back to listener without a prompt. This is where the `force` parameter comes in. When it is set to `true` the other party will not receive a confirmation `roleChangeRequest` but instead will straight away receive a new set of updated permissions and stop publishing. `roleUpdated` callback will still be fired so that the app can update the user's UI state.\n  \n\n## ❌ Error Handling\n\nWhen you make an API call to access an HMS SDK, the SDK may return error codes. ErrorCodes are returned when a problem that cannot be recovered without app intervention has occurred.\n\nThese are returned as `HMSError` in the `func on(error: HMSError)` callback of the `HMSUpdateListner`.\n\nFollowing are the different error codes that are returned by the SDK . Before returning any error code, SDK retries the errors\\(whichever is possible\\).\n\n| **Error Code** | **Cause of the error**                                 | **Action to be taken**                                                                                     |\n| :------------- | :----------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |\n| **1003**       | Websocket disconnected - Happens due to network issues | Mention user to check their network connection or try again after some time.                                |\n| **2002**       | Invalid Endpoint URL                                   | Check the endpoint provided while calling `join` on `HMSSDK`.                                               |\n| **2003**       | Endpoint is not reachable                              | Mention user to check their network connection or try again after some time.                                |\n| **2004**       | Token is not in proper JWT format                      | The token passed while calling `join` is not in correct format. Retry getting a new token.                  |\n| **3001**       | Cant Access Capture Device                             | Ask user to check permission granted to audio/video capture devices.                                        |\n| **3002**       | Capture Device is not Available                        | Ask user to check if the audio/video capture device is connected or not.                                    |\n| **3003**       | Capture device is in use by some other application     | Show notification to user mentioning that the capturing device is used by some other application currently. |\n| **3008**       | Browser has throw an autoplay exception                | Show notification to user mentioning that the browser blocked autoplay |\n| **4001**       | WebRTC error                                           | Some webRTC error has occured. Need more logs to debug.                                                     |\n| **4002**       | WebRTC error                                           | Some webRTC error has occured. Need more logs to debug.                                                     |\n| **4003**       | WebRTC error                                           | Some webRTC error has occured. Need more logs to debug.                                                     |\n| **4004**       | WebRTC error                                           | Some webRTC error has occured. Need more logs to debug.                                                     |\n| **4005**       | ICE Connection Failed due to network issue             | Mention user to check their network connection or try again after some time.                                |\n| **5001**       | Trying to join a room which is already joined          | Trying to join an already joined room.                                                                     |\n| **6002**       | webRTC Error: Error while renegotiating                | Please try again.                                                                                           |\n| **40101**      | Token Error: Invalid Access Key                        | Access Key provided in the token is wrong.                                                                  |\n| **40102**      | Token Error: Invalid Room Id                           | RoomID provided in the token is wrong.                                                                      |\n| **40103**      | Token Error: Invalid Auth Id                           | AuthID provided in the token is wrong.                                                                      |\n| **40104**      | Token Error: Invalid App Id                            | App ID provided in the token is wrong.                                                                      |\n| **40105**      | Token Error: Invalid Customer Id                       | Customer Id provided in the token is wrong.                                                                 |\n| **40107**      | Token Error: Invalid User Id                           | User ID provided in the token is wrong.                                                                     |\n| **40108**      | Token Error: Invalid Role                              | The role provided in the token is wrong.                                                                    |\n| **40109**      | Token Error: Bad JWT Token                             | Bad JWT Token.                                                                                              |\n| **40100**      | Generic Error                                          | Need to debug further with logs.                                                                            |\n| **40001**      | Invalid Room                                           | Room ID provided while fetching the token is an invalid room.                                               |\n| **40002**      | Room Mismatched with Token                               | Room ID provided while fetching the token does not match.                                                   |\n| **40004**      | Peer already joined                                    | Peer who is trying to join has already joined the room.                                                     |\n| **41001**      | Peer is gone                                           | The peer is no more present in the room.                                                                    |\n\n👀 Checkout the sample implementation in the [Example app folder](https://github.com/100mslive/100ms-ios-sdk/tree/main/Example).\n\n📲 Download the 100ms fully featured Sample iOS app here: https://testflight.apple.com/join/dhUSE7N8\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F100mslive%2F100ms-ios-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F100mslive%2F100ms-ios-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F100mslive%2F100ms-ios-sdk/lists"}