I am using PushToTalk in my project for using only listing audio.
steps :-
- App Launch :- Create PTT Channel
- PTT Token :- Send Token in Server
- App Kill :- It's Automatically restored channel using :- channelDescriptor(restoredChannelUUID channelUUID: UUID) -> PTChannelDescriptor
- Play audio given by incomingPushResult method
issue :-
-
I am receiving an audio link through incomingPushResult.
-
When incomingPushResult is called, it automatically restores the channel. However, the channel has already been created, resulting in two channels being created.
-
When I send the link from the server, the audio plays properly.
-
However, if I resend the same link after 5-6 seconds, the audio does not play.
-
After I leave the first channel, the same audio starts playing in the second channel. When I send the link again, the audio does not play because I left the first (main) channel.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}
Task {
await self.createChannel()
}
return true
}
func createChannel() async {
do {
channelManager = try await PTChannelManager.channelManager(delegate: self, restorationDelegate: self)
let channelImage = UIImage(named: "ic_p")
channelDescriptor = PTChannelDescriptor(name: "Pikachu", image: channelImage)
let channelUUID = UUID()
self.currentChannelUUID = channelUUID
channelManager?.requestJoinChannel(channelUUID: channelUUID, descriptor: channelDescriptor!)
print("PTT creating channel")
} catch {
print("Error creating channel: \(error)")
}
}
func incomingPushResult(channelManager: PTChannelManager, channelUUID: UUID, pushPayload: [String : Any]) -> PTPushResult {
guard let data = pushPayload["data"] as? [String: Any],
let mediaLink = data["media_link"] as? String else {
return .leaveChannel
}
print("incomingPTT")
// URL to fetch the audio data from
self.audioURL = mediaLink
// Play the audio from the URL
DispatchQueue.main.async {
self.playSound(url: self.audioURL)
}
let participant = PTParticipant(name: mediaLink, image: .checkmark)
return .activeRemoteParticipant(participant)
}
func channelDescriptor(restoredChannelUUID channelUUID: UUID) -> PTChannelDescriptor {
let channelImage = UIImage(named: "ic_r")
return PTChannelDescriptor(name: "Restored Channel", image: channelImage)
}
func channelManager(_ channelManager: PTChannelManager, didActivate audioSession: AVAudioSession) {
print("Activated audio session")
self.playSound(url: self.audioURL)
}
Output: -
- App Launch
- After App Kill Play audio :- Audio Play Success and leave the channel
(Before Leave Channel View)
- After Leave Channel View
So, the immediate issue here is this:
func createChannel() async {
do {
...
channelManager?.requestJoinChannel(channelUUID: channelUUID, descriptor: channelDescriptor!)
...
} catch {
print("Error creating channel: \(error)")
}
}
You cannot do that. Your app is only allowed to "directly" join a channel when it's in the foreground, so "requestJoinChannel" should only be called from the foreground and, more likely, should probably be part of your app interface where the user can start a PTT session (not automatic).
In the background, it's not necessary as "channelDescriptor(restoredChannelUUID...)" means that the system has already joined the "channel".
However, that leads to the bigger conceptual issue with the PTT framework, which is that you shouldn't think of "our channel" as the same thing as whatever your app considers "a channel". With the benefit of hindsight, we should not have used the term "channel" at all ("session" would have a been a much better term), as the term is very widely used in PTT apps which creates expectations that don't match the system actual behavior.
Your app should not attempt to create/join multiple PTChannel's, as it greatly complicates the entire architecture without providing any actual benefit. Your app can have as many channels (or whatever you choose to call them) as it wants, but it should just modify PTChannelDescriptor of it's only PTChannel to tell the user what's going on.
Note that the documentation does indicate that this is what you should do:
"You can activate only one channel at a time. A nil value indicates there isn’t an active Push to Talk channel. When this value isn’t nil, the channel is active in the user interface, and the ephemeral push token is usable."
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware