Skip to content

Add subscriber list and count methods #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions WebRTC-Sample-App/ConferenceViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ open class ConferenceViewController: UIViewController , AVCaptureVideoDataOutpu

//this publishes stream to the room
self.publisherStreamId = generateRandomAlphanumericString(length: 10);
self.conferenceClient?.publish(streamId: self.publisherStreamId, token: "", mainTrackId: roomId);
self.conferenceClient?.publish(streamId: self.publisherStreamId, mainTrackId: roomId);

//this plays the streams in the room

Expand Down Expand Up @@ -96,20 +96,24 @@ extension ConferenceViewController: AntMediaClientDelegate
removePlayers();
}
public func playStarted(streamId: String) {
print("play started");
debugPrint("play started");
conferenceClient?.speakerOn()

}

public func trackAdded(track: RTCMediaStreamTrack, stream: [RTCMediaStream]) {

AntMediaClient.printf("Track is added with id:\(track.trackId)")


if let videoTrack = track as? RTCVideoTrack
{
remoteViewTrackMap.append(videoTrack);
Run.onMainThread {
self.collectionView.reloadData()
}
}

}

public func trackRemoved(track: RTCMediaStreamTrack) {
Expand Down Expand Up @@ -139,7 +143,7 @@ extension ConferenceViewController: AntMediaClientDelegate
AntMediaClient.printf("Publish started for stream:\(streamId)")

//this plays the streams in the room
self.conferenceClient?.play(streamId: self.roomId);
self.conferenceClient?.play(streamId: self.roomId, subscriberId: "subscriberId", subscriberName: "subscriberName", disableTracksByDefault:false);

conferenceClient?.getBroadcastObject(forStreamId: self.roomId)

Expand Down
108 changes: 100 additions & 8 deletions WebRTCiOSSDK/api/AntMediaClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public enum AntMediaClientMode: Int {
case conference = 4
case unspecified = 5



func getLeaveMessage() -> String {
switch self {
case .join:
Expand Down Expand Up @@ -51,6 +53,7 @@ public enum AntMediaClientMode: Int {
}

open class AntMediaClient: NSObject, AntMediaClientProtocol {


internal static var isDebug: Bool = false
internal static var isVerbose: Bool = false
Expand Down Expand Up @@ -128,6 +131,14 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
var disableTrackId: String?

var reconnectIfRequiresScheduled: Bool = false

var subscriberId: String = ""
var subscriberCode: String = ""
var subscriberName: String = ""

var playOnlyDataChannel : Bool = false
var disableTracksByDefault: Bool = false
var publishOnlyDataChannel : Bool = false

struct HandshakeMessage: Codable {
var command: String?
Expand All @@ -138,8 +149,15 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
var mode: String?
var mainTrack: String?
var trackList: [String]
var subscriberId: String?
var subscriberCode: String?
var subscriberName: String?
var onlyDataChannel: Bool?
var disableTracksByDefault: Bool?
}



public override init() {
}

Expand Down Expand Up @@ -211,7 +229,9 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
AntMediaClient.printf("Disable track id is not set \(String(describing: self.disableTrackId))")
}

let handShakeMesage = HandshakeMessage(command: mode.getName(), streamId: streamId, token: token, video: self.videoEnable, audio: self.audioEnable, mainTrack: self.mainTrackId, trackList: trackList)
let handShakeMesage = HandshakeMessage(command: mode.getName(), streamId: streamId, token: token, video: self.videoEnable, audio: self.audioEnable, mainTrack: self.mainTrackId, trackList: trackList,
subscriberId: self.subscriberId, subscriberCode: self.subscriberCode, subscriberName: self.subscriberName, onlyDataChannel: mode == .publish ? self.publishOnlyDataChannel : self.playOnlyDataChannel,
disableTracksByDefault: self.disableTracksByDefault)

let json = try! JSONEncoder().encode(handShakeMesage)
return String(data: json, encoding: .utf8)!
Expand Down Expand Up @@ -353,9 +373,24 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
RTCAudioSessionConfiguration.setWebRTC(RTCAudioSessionConfiguration())
}

public func publish(streamId: String, token: String = "", mainTrackId: String = "") {
public func publish(streamId: String, token: String = "", mainTrackId: String = "", subsriberId: String = "", subscriberCode: String = "", subscriberName: String = "", onlyDataChannel: Bool=false, videoEnabled: Bool = true) {

self.publisherStreamId = streamId
self.publishOnlyDataChannel = onlyDataChannel
self.videoEnable = videoEnabled

if !subsriberId.isEmpty {
self.subscriberId = subsriberId
}

if !subscriberCode.isEmpty {
self.subscriberCode = subscriberCode
}

if !subscriberName.isEmpty {
self.subscriberName = subscriberName
}

// reset default webrtc audio configuation to capture audio and mic
resetDefaultWebRTCAudioConfiguation()
initPeerConnection(streamId: streamId, mode: AntMediaClientMode.publish, token: token)
Expand All @@ -375,9 +410,26 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
}
}

public func play(streamId: String, token: String = "") {
public func play(streamId: String, token: String = "",
subscriberId: String = "", subscriberCode: String = "", subscriberName: String = "",
onlyDataChannel: Bool=false, disableTracksByDefault: Bool=false)
{

self.playerStreamId = streamId
self.playOnlyDataChannel = onlyDataChannel
self.disableTracksByDefault = disableTracksByDefault

if !subscriberId.isEmpty {
self.subscriberId = subscriberId
}

if !subscriberCode.isEmpty {
self.subscriberCode = subscriberCode
}

if !subscriberName.isEmpty {
self.subscriberName = subscriberName
}

if !token.isEmpty {
self.playToken = token
Expand Down Expand Up @@ -483,6 +535,7 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
open func initPeerConnection(streamId: String = "", mode: AntMediaClientMode = .unspecified, token: String = "") {

let id = getStreamId(streamId)
self.mode = mode;

if self.webRTCClientMap[id] == nil {
AntMediaClient.printf("Has wsClient? (start) : \(String(describing: self.webRTCClientMap[id]))")
Expand Down Expand Up @@ -867,7 +920,7 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
// clean the connection
self.webRTCClientMap.removeValue(forKey: streamId)?.disconnect()
AntMediaClient.printf("Reconnecting to publish the stream:\(streamId)")
self.publish(streamId: streamId)
self.publish(streamId: streamId, onlyDataChannel: self.publishOnlyDataChannel, videoEnabled: self.videoEnable)
} else {
AntMediaClient.printf("Not trying to reconnect to publish the stream:\(streamId) because ice connection state is not disconnected")
}
Expand All @@ -888,7 +941,7 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
// clean the connection
self.webRTCClientMap.removeValue(forKey: streamId)?.disconnect()
AntMediaClient.printf("Reconnecting to play the stream:\(streamId)")
self.play(streamId: streamId)
self.play(streamId: streamId, onlyDataChannel: self.playOnlyDataChannel, disableTracksByDefault:self.disableTracksByDefault)
} else {
AntMediaClient.printf("Not trying to reconnect to play the stream:\(streamId) because ice connection state is not disconnected")
}
Expand Down Expand Up @@ -1037,6 +1090,29 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
let streamId = message[STREAM_ID] as? String ?? ""
self.delegate?.eventHappened(streamId: streamId, eventType: definition, payload: message)
}
else if definition == SUBSCRIBER_COUNT {
let streamId = message[STREAM_ID] as? String ?? ""
let count = message["count"] as! Int
self.delegate?.subscriberCount(streamId: streamId, subscriberCount: count);
}
else if definition == SUBSCRIBER_LIST_NOTIFICATION {
let streamId = message[STREAM_ID] as? String ?? ""
if let subscriberListJSONArray = message["subscriberList"] as? [String] {
var subscribers: [Subscriber] = []

for jsonString in subscriberListJSONArray {
if let data = jsonString.data(using: .utf8) {
do {
let subscriber = try JSONDecoder().decode(Subscriber.self, from: data)
subscribers.append(subscriber)
} catch {
print("Failed to decode subscriber: \(error)")
}
}
}
self.delegate?.subscriberList(streamId: streamId, subscriberList: subscribers)
}
}
case ROOM_INFORMATION_COMMAND:
if let updatedStreamsInTheRoom = message[STREAMS] as? [String] {
// check that there is a new stream exists
Expand Down Expand Up @@ -1274,6 +1350,24 @@ open class AntMediaClient: NSObject, AntMediaClientProtocol {
)
}

public func getSubscriberCount(streamId id: String) {
sendCommand(
command: GET_SUBSCRIBER_COUNT_COMMAND,
streamId: id
)
}

public func getSubscriberList(streamId id: String, offset: Int, limit: Int) {

let jsonString = [
COMMAND: GET_SUBSCRIBER_LIST_COMMAND,
STREAM_ID: id,
OFFSET: offset,
SIZE: limit].json

webSocket?.write(string: jsonString)
}

func invalidateTimers() {
audioLevelGetterTimer?.invalidate()
audioLevelGetterTimer = nil
Expand Down Expand Up @@ -1345,9 +1439,7 @@ extension AntMediaClient: WebRTCClientDelegate {
if let eventType = json?[EVENT_TYPE] {
// event happened
if let incomingStreamId = json?[STREAM_ID] {

self.delegate?.eventHappened(streamId: incomingStreamId as! String, eventType: eventType as! String)


self.delegate?.eventHappened(
streamId: incomingStreamId as! String,
eventType: eventType as! String
Expand Down
23 changes: 23 additions & 0 deletions WebRTCiOSSDK/api/AntMediaClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class StreamInformation {
}
}

public struct Subscriber: Codable {
let subscriberId: String
let subscriberName: String
}

public protocol AntMediaClientDelegate: AnyObject {

/**
Expand Down Expand Up @@ -178,6 +183,16 @@ public protocol AntMediaClientDelegate: AnyObject {
If it's 0, it means it's silent. If it's 1, it means audio is max.
*/
func audioLevelChanged(_ client: AntMediaClient, audioLevel: Double, hasAudio: Bool)

/**
The delegate method is called as response to getSubscriberCount for the stream
*/
func subscriberCount(streamId:String, subscriberCount:Int)

/**
The delegate method is called as a response to getSubscriberList for the stream
*/
func subscriberList(streamId:String, subscriberList:[Subscriber])
}

public extension AntMediaClientDelegate {
Expand Down Expand Up @@ -279,4 +294,12 @@ public extension AntMediaClientDelegate {
AntMediaClient.printf("streamId: \(streamId) stats received")
}

func subscriberCount(streamId:String, subscriberCount:Int) {
AntMediaClient.printf("subscriberCount for: \(streamId) is received as \(subscriberCount)")
}

func subscriberList(streamId:String, subscriberList:[Subscriber]) {
AntMediaClient.printf("subscriberList for: \(streamId) is received: \(subscriberList)")
}

}
38 changes: 35 additions & 3 deletions WebRTCiOSSDK/api/AntMediaClientProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import WebRTC

let COMMAND = "command"
let STREAM_ID = "streamId"
let OFFSET = "offset"
let SIZE = "size"
let TRACK_ID = "trackId"
let ENABLED = "enabled"
let TOKEN_ID = "token"
Expand All @@ -35,8 +37,14 @@ let EVENT_TYPE_MIC_UNMUTED = "MIC_UNMUTED"
let EVENT_TYPE_CAM_TURNED_OFF = "CAM_TURNED_OFF"
let EVENT_TYPE_CAM_TURNED_ON = "CAM_TURNED_ON"
let GET_BROADCAST_OBJECT_COMMAND = "getBroadcastObject"
let GET_SUBSCRIBER_COUNT_COMMAND = "getSubscriberCount"
let GET_SUBSCRIBER_LIST_COMMAND = "getSubscribers"

let BROADCAST_OBJECT_NOTIFICATION = "broadcastObject"
public let RESOLUTION_CHANGE_INFO_COMMAND = "resolutionChangeInfo"
public let SUBSCRIBER_COUNT = "subscriberCount"
public let SUBSCRIBER_LIST_NOTIFICATION = "subscriberList";

public let EVENT_TYPE_TRACK_LIST_UPDATED = "TRACK_LIST_UPDATED"
public let EVENT_TYPE_VIDEO_TRACK_ASSIGNMENT_LIST = "VIDEO_TRACK_ASSIGNMENT_LIST"

Expand Down Expand Up @@ -120,17 +128,31 @@ public protocol AntMediaClientProtocol {
/**
Publish stream to the server with streamId and roomId.
- Parameters
- streamId: the id of the stream that is going to be published.
- streamId: the id of the stream that is going to be published. Required
- mainTrackId: the id of the main stream or conference room that this stream will be published. It's optional value
- token: The access token to publish the stream. If JWT or any other token security is enabled in the Ant Media Server, this field is required
- subsriberId: The subscriberId. If TOTP is enabled in server it is mandatory otherwise optional to have some field s
- subscriberCode: The subscriber code is the TOTP code which is mandatory if the TOTP security is enabled on the server side
- subscriberName: Subscriber name which is optional
- onlyDataChannel: Option to publish for data channel not audio/video
- videoEnabled: Send stream with video or not
*/
func publish(streamId: String, token: String, mainTrackId: String)
func publish(streamId: String, token: String, mainTrackId: String, subsriberId: String, subscriberCode: String, subscriberName: String,
onlyDataChannel: Bool, videoEnabled: Bool)

/**
Starts to play a stream on the server side
- Parameters
- streamId: the id of the stream or id of the conference room. It supports playing both of them
- token: The access token to publish the stream. If JWT or any other token security is enabled in the Ant Media Server, this field is required
- subscriberId: The subscriberId. If TOTP is enabled in server it is mandatory otherwise optional to have some field s
- subscriberCode: The subscriber code is the TOTP code which is mandatory if the TOTP security is enabled on the server side
- subscriberName: Subscriber name which is optional
- onlyDataChannel: Option to publish for data channel not audio/video
*/
func play(streamId: String, token: String)
func play(streamId: String, token: String,
subscriberId: String, subscriberCode: String, subscriberName: String, onlyDataChannel: Bool,
disableTracksByDefault: Bool)

/**
Sets the camera position front or back. This method is effective if it's called before `initPeerConnection()` and `start()` method.
Expand Down Expand Up @@ -412,6 +434,16 @@ public protocol AntMediaClientProtocol {
*/
func getBroadcastObject(forStreamId id: String)

/**
Get the number of subscribers for the stream id
*/
func getSubscriberCount(streamId id: String)

/**
Get the subscriber list for the stream id
*/
func getSubscriberList(streamId id: String, offset: Int, limit: Int)

/**
Register for Audio Level Extraction to get the audioLevel from the microphone. It's good to use to detect if user is speaking when he muted himself.
When this method is called, `audioLevelChanged` delegate method will be called automatically
Expand Down