Skip to content

Codec negotiation #606

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

Merged
merged 58 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
3c9ca5e
Show more controls with one user
ipavlidakis Nov 22, 2024
0b5a376
Add comments
ipavlidakis Dec 13, 2024
ba3e832
Update ActionHandlers
ipavlidakis Dec 13, 2024
e3f0d74
Remove unnecessary files
ipavlidakis Dec 13, 2024
2692a6d
Update logic for layers calculation
ipavlidakis Dec 16, 2024
694933c
Fix av1 layers rewrite
ipavlidakis Dec 17, 2024
ebbdd02
Fix screensharing missing due to empty rid
ipavlidakis Dec 17, 2024
b632a8b
Fix low quality issue
ipavlidakis Dec 18, 2024
187b5eb
Fix trackInfo layer
ipavlidakis Dec 18, 2024
a45e2d0
Fix unnecessarily updating transceivers
ipavlidakis Dec 18, 2024
9daed4c
Update pip and fix screensharing
ipavlidakis Dec 18, 2024
7da2bc6
Update pip tracks when app becomes active again
ipavlidakis Dec 18, 2024
285c296
Maintain tracks in the SetPublisherRequest after codec disabled or un…
ipavlidakis Dec 18, 2024
bd6ee54
Initial tests and changes
ipavlidakis Dec 17, 2024
e75d835
Updated mocks
ipavlidakis Dec 17, 2024
058258c
Add tests I
ipavlidakis Dec 17, 2024
bb8c080
WIP
ipavlidakis Dec 18, 2024
2d4a6bc
Make tests compile again
ipavlidakis Dec 19, 2024
6ca71ed
Add/update tests
ipavlidakis Dec 19, 2024
e517e6f
Add/Update tests II
ipavlidakis Dec 20, 2024
2f2d239
Add/Update tests III
ipavlidakis Dec 20, 2024
a1675ba
Update publishOptions event handling to align with SFU
ipavlidakis Dec 20, 2024
ed6cd71
Add/update tests IV
ipavlidakis Dec 20, 2024
68ae340
Announce expected tracks on migration/rejoin
ipavlidakis Dec 20, 2024
d84ed22
Fixed the tests
martinmitrevski Dec 23, 2024
3e4a0b0
Tests cleanup
martinmitrevski Dec 23, 2024
389209b
Fixed wrong target membership
martinmitrevski Dec 23, 2024
1e34cae
Fixed tests
martinmitrevski Dec 23, 2024
6194927
Misuse of compact map, fix build on Xcode 15
martinmitrevski Dec 23, 2024
60c212b
Sending codec in setPublisher
martinmitrevski Dec 23, 2024
53f2c3b
Small fixes
martinmitrevski Dec 25, 2024
6f4783c
Fix muted track info and processing time
ipavlidakis Dec 30, 2024
d215eac
Updates
ipavlidakis Dec 30, 2024
88ae8e4
Update year
ipavlidakis Jan 3, 2025
9652de3
Added publish option id to the track info (#631)
martinmitrevski Jan 3, 2025
497c023
Send publishOptionId with TrackInfo
ipavlidakis Jan 3, 2025
a0af992
Updates
ipavlidakis Jan 3, 2025
25a3ef3
Updates
ipavlidakis Jan 3, 2025
b0db491
Reenable LocalAudioMediaAdapter tests
ipavlidakis Jan 3, 2025
ca36549
Correlate transceivers withs tracks and publishOptions
ipavlidakis Jan 3, 2025
66f58fe
bug fixes
ipavlidakis Jan 7, 2025
d133b00
bug and tests fixes/additions
ipavlidakis Jan 7, 2025
070d6be
Decouple stats collection from delivery
ipavlidakis Jan 8, 2025
6ee815e
Update active codec in demo stats
ipavlidakis Jan 8, 2025
fa05d3c
Update stats collection + tests
ipavlidakis Jan 8, 2025
f1789c7
Fix localAudioMediaAdapter tests
ipavlidakis Jan 8, 2025
6a98f8b
Fix/add tests
ipavlidakis Jan 8, 2025
80ed8b7
Add track info tests for localVideoMediaAdapter
ipavlidakis Jan 8, 2025
7bd4b17
Fix swiftui tests
ipavlidakis Jan 8, 2025
ddd4af5
Fix compilation errors on Xcode 15
ipavlidakis Jan 8, 2025
627f118
Add tests
ipavlidakis Jan 9, 2025
5077271
Final touches
ipavlidakis Jan 9, 2025
a6c8d85
Fix xcode 15 format issue
ipavlidakis Jan 9, 2025
49ca88d
Fix camera switch
ipavlidakis Jan 9, 2025
e5d9b7f
Add logging for SetPulisherResponse
ipavlidakis Jan 10, 2025
99d97c5
Send audio codec with trackInfo
ipavlidakis Jan 10, 2025
338a547
Relax updateSubscription errors severity to avoid unnecessary reconne…
ipavlidakis Jan 13, 2025
a150a55
[Feature]Mute track on background when isMultitaskingCameraAccessSupp…
ipavlidakis Jan 14, 2025
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### ✅ Added
- CallKit availability policies allows you to control wether `Callkit` should be enabled/disabled based on different rules [#611](https://github.com/GetStream/stream-video-swift/pull/611)
- Support for setting a ringtone for CallKit calls [#628](https://github.com/GetStream/stream-video-swift/pull/628)
- Codec negotiation during calls (#606)(https://github.com/GetStream/stream-video-swift/pull/606)
- When moving to background/foreground while your video is active, if the device doesn't support [AVCaptureSession.isMultitaskingCameraAccessSupported](https://developer.apple.com/documentation/avfoundation/avcapturesession/ismultitaskingcameraaccesssupported) the SDK will mute/unmute the track to ensure that other participants have some feedback from your track. [#633](https://github.com/GetStream/stream-video-swift/pull/633)

### 🐞 Fixed
- By observing the `CallKitPushNotificationAdapter.deviceToken` you will be notified with an empty `deviceToken` value, once the object unregister push notifications. [#608](https://github.com/GetStream/stream-video-swift/pull/608)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ final class OSLogDestination: BaseLogDestination {
extendedDetails += "[\(logDetails.functionName)] "
}

let extendedMessage = "\(extendedDetails)> \(logDetails.message)"
var extendedMessage = "\(extendedDetails)> \(logDetails.message)"
if let error = logDetails.error {
extendedMessage += "[Error: \(error)]"
}
let formattedMessage = LogConfig
.formatters
.reduce(extendedMessage) { $1.format(logDetails: logDetails, message: $0) }
Expand Down
4 changes: 1 addition & 3 deletions DemoApp/Sources/Controls/DemoControls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ struct AppControlsWithChat: View {

var body: some View {
HStack {
if viewModel.callParticipants.count > 1 {
MoreControlsIconView(viewModel: viewModel)
}
MoreControlsIconView(viewModel: viewModel)

#if !targetEnvironment(simulator)
if !ProcessInfo.processInfo.isiOSAppOnMac {
Expand Down
31 changes: 20 additions & 11 deletions DemoApp/Sources/Views/StatsView/DemoStatsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,7 @@ struct DemoStatsView: View {
viewModel,
title: "PUBLISH RESOLUTION",
value: "none",
titleTransformer: { report in
let codec = report?
.publisherBaseStats
.last?
.codec
if let codec = codec?.split(separator: "/").last {
return "PUBLISH RESOLUTION(\(codec))"
} else {
return "PUBLISH RESOLUTION"
}
},
titleTransformer: { publishQualityFormatter($0) },
valueTransformer: { resolutionFormatter(from: $0?.publisherStats) }
)
} _: {
Expand Down Expand Up @@ -164,6 +154,25 @@ struct DemoStatsView: View {
}
}

private func publishQualityFormatter(
_ report: CallStatsReport?
) -> String {
let activeCodecs = report?
.publisherBaseStats
.filter { $0.framesPerSecond > 0 }
.compactMap(\.codec)
.compactMap { $0.split(separator: "/").last }
let uniqueActiveCodecs = Set(activeCodecs ?? [])
.sorted()
.joined(separator: ",")

guard !uniqueActiveCodecs.isEmpty else {
return "PUBLISH RESOLUTION"
}

return "PUBLISH RESOLUTION(\(uniqueActiveCodecs))"
}

private func resolutionFormatter(
from report: AggregatedStatsReport?
) -> String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct DemoWaitingLocalUserView<Factory: DemoAppViewFactory>: View {
.navigationViewStyle(.stack)
}
}
.presentsMoreControls(viewModel: viewModel)
.alignedToReadableContentGuide()
.padding(.bottom)
} else {
Expand Down
58 changes: 58 additions & 0 deletions Sources/StreamVideo/Models/AudioCodec.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// Copyright © 2025 Stream.io Inc. All rights reserved.
//

import Foundation
import StreamWebRTC

/// Represents different audio codecs.
public enum AudioCodec: String, CustomStringConvertible, Sendable {
case opus
case red
case unknown

/// Returns the raw value of the codec, which corresponds to its name.
public var description: String {
rawValue
}

/// Initializes an `AudioCodec` instance from WebRTC codec parameters.
///
/// This initializer maps a WebRTC codec (`RTCRtpCodecParameters`) to the
/// corresponding `AudioCodec` value. If the codec name matches `opus` or
/// `red`, the respective case is assigned; otherwise, it defaults to
/// `.unknown`.
///
/// - Parameter source: The `RTCRtpCodecParameters` object containing codec
/// details such as the codec name.
init(_ source: RTCRtpCodecParameters) {
switch source.name.lowercased() {
case AudioCodec.opus.rawValue:
self = .opus
case AudioCodec.red.rawValue:
self = .red
default:
self = .unknown
}
}

/// Initializes an `AudioCodec` instance from SFU codec model parameters.
///
/// This initializer maps an SFU codec model (`Stream_Video_Sfu_Models_Codec`)
/// to the corresponding `AudioCodec` value. If the codec name matches `opus`
/// or `red`, the respective case is assigned; otherwise, it defaults to
/// `.unknown`.
///
/// - Parameter source: The `Stream_Video_Sfu_Models_Codec` object containing
/// codec details such as the codec name.
init(_ source: Stream_Video_Sfu_Models_Codec) {
switch source.name.lowercased() {
case AudioCodec.opus.rawValue:
self = .opus
case AudioCodec.red.rawValue:
self = .red
default:
self = .unknown
}
}
}
26 changes: 26 additions & 0 deletions Sources/StreamVideo/Models/CallParticipant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,32 @@ public struct CallParticipant: Identifiable, Sendable, Hashable {
)
}

public func withUpdated(trackLookupPrefix: String) -> CallParticipant {
CallParticipant(
id: id,
userId: userId,
roles: roles,
name: name,
profileImageURL: profileImageURL,
trackLookupPrefix: trackLookupPrefix,
hasVideo: hasVideo,
hasAudio: hasAudio,
isScreenSharing: isScreensharing,
showTrack: showTrack,
track: track,
trackSize: trackSize,
screenshareTrack: screenshareTrack,
isSpeaking: isSpeaking,
isDominantSpeaker: isDominantSpeaker,
sessionId: sessionId,
connectionQuality: connectionQuality,
joinedAt: joinedAt,
audioLevel: audioLevel,
audioLevels: audioLevels,
pin: pin
)
}

public func withUpdated(
isSpeaking: Bool,
audioLevel: Float
Expand Down
Loading