diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d5e2d30 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.caf filter=lfs diff=lfs merge=lfs -text diff --git a/LiveKitExample-dev.xcworkspace/xcshareddata/swiftpm/Package.resolved b/LiveKitExample-dev.xcworkspace/xcshareddata/swiftpm/Package.resolved index fde145b..017ae68 100644 --- a/LiveKitExample-dev.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/LiveKitExample-dev.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "f4d08983a90380a6e5bb0db48e835cd578e5e6a9b2b74c9ac261d3d0bab1d7c2", + "originHash" : "a05879f3bc2bf63c534796adfb61bd78fdf0af76375573e6ae3e5f509a522dda", "pins" : [ { "identity" : "jwt-kit", @@ -73,15 +73,6 @@ "version" : "1.0.0" } }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa", - "version" : "1.6.3" - } - }, { "identity" : "swift-protobuf", "kind" : "remoteSourceControl", @@ -96,8 +87,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/livekit/webrtc-xcframework.git", "state" : { - "revision" : "26be1457f076237df4d42c15c3bc23b0841d3c21", - "version" : "137.7151.9" + "revision" : "5b40f56c637369064b9c82e8f9cfa820f942658f", + "version" : "137.7151.10" } } ], diff --git a/LiveKitExample.xcodeproj/project.pbxproj b/LiveKitExample.xcodeproj/project.pbxproj index b0d1aac..87b6623 100644 --- a/LiveKitExample.xcodeproj/project.pbxproj +++ b/LiveKitExample.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 56; + objectVersion = 70; objects = { /* Begin PBXBuildFile section */ @@ -101,6 +101,21 @@ D7AA477A285A0FFC00EB41AE /* SampleHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleHandler.swift; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 689958FD2EB4B9C20037CECF /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + "tadaa-mono.caf", + "tadaa-stereo.caf", + ); + target = 68A50E8E2C4C1C4C00D2DE17 /* LiveKitExample */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 684A6D8A2EB40C1A00FF6EB1 /* Resources */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (689958FD2EB4B9C20037CECF /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Resources; sourceTree = ""; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 683F05F0273F96B20080C7AC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -210,6 +225,7 @@ 68B38536271E780600711D5F = { isa = PBXGroup; children = ( + 684A6D8A2EB40C1A00FF6EB1 /* Resources */, 68A50EDE2C4C1ED500D2DE17 /* Multiplatform */, 6865EA2427513B4500FFAFC3 /* iOS */, 68B38544271E780700711D5F /* Products */, @@ -754,8 +770,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/livekit/client-sdk-swift"; requirement = { - kind = exactVersion; - version = 2.8.1; + branch = "hiroshi/sound-player"; + kind = branch; }; }; B5C2EF142D0114C800FAC766 /* XCRemoteSwiftPackageReference "components-swift" */ = { diff --git a/LiveKitExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/LiveKitExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 043fe31..85b64df 100644 --- a/LiveKitExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/LiveKitExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/livekit/client-sdk-swift", "state" : { - "revision" : "57448c954a87ed827803914e9fee5e45ef359ba2", - "version" : "2.8.1" + "branch" : "hiroshi/sound-player", + "revision" : "d14b092b58fdc83465506e0c634283f925c88e7f" } }, { @@ -19,6 +19,15 @@ "version" : "0.1.5" } }, + { + "identity" : "jwt-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/jwt-kit.git", + "state" : { + "revision" : "13e7513b3ba0afa13967daf77af2fb4ad087306c", + "version" : "4.13.5" + } + }, { "identity" : "keychainaccess", "kind" : "remoteSourceControl", @@ -37,6 +46,15 @@ "version" : "4.1.1" } }, + { + "identity" : "swift-asn1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-asn1.git", + "state" : { + "revision" : "40d25bbb2fc5b557a9aa8512210bded327c0f60d", + "version" : "1.5.0" + } + }, { "identity" : "swift-collections", "kind" : "remoteSourceControl", @@ -47,12 +65,12 @@ } }, { - "identity" : "swift-log", + "identity" : "swift-crypto", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", + "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2", - "version" : "1.6.4" + "revision" : "95ba0316a9b733e92bb6b071255ff46263bbe7dc", + "version" : "3.15.1" } }, { @@ -60,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "2547102afd04fe49f1b286090f13ebce07284980", - "version" : "1.31.1" + "revision" : "c169a5744230951031770e27e475ff6eefe51f9d", + "version" : "1.33.3" } }, { @@ -69,8 +87,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/livekit/webrtc-xcframework.git", "state" : { - "revision" : "26be1457f076237df4d42c15c3bc23b0841d3c21", - "version" : "137.7151.9" + "revision" : "5b40f56c637369064b9c82e8f9cfa820f942658f", + "version" : "137.7151.10" } } ], diff --git a/Multiplatform/Controllers/AppContext.swift b/Multiplatform/Controllers/AppContext.swift index 1a43c43..9057e95 100644 --- a/Multiplatform/Controllers/AppContext.swift +++ b/Multiplatform/Controllers/AppContext.swift @@ -14,10 +14,15 @@ * limitations under the License. */ +import AVFAudio import Combine import LiveKit import SwiftUI +let soundPlayer = SoundPlayer() + +nonisolated(unsafe) var audioPlayer: AVAudioPlayer? + // This class contains the logic to control behavior of the whole app. @MainActor final class AppContext: ObservableObject { @@ -95,6 +100,21 @@ final class AppContext: ObservableObject { didSet { AudioManager.shared.mixer.appVolume = appVolume } } + func playSoundEffectNormal() async throws { + guard let url = Bundle.main.url(forResource: "tadaa-mono", withExtension: "caf") else { + throw NSError(domain: "Audio", code: 1, userInfo: [NSLocalizedDescriptionKey: "tadaa.caf not found in bundle"]) + } + + // Create and play the audio player + audioPlayer = try AVAudioPlayer(contentsOf: url) + audioPlayer?.prepareToPlay() + audioPlayer?.play() + } + + func playSoundEffectAPI() async throws { + try await soundPlayer.play(id: "tadaa") + } + init(store: ValueStore) { self.store = store @@ -121,5 +141,18 @@ final class AppContext: ObservableObject { inputDevices = AudioManager.shared.inputDevices outputDevice = AudioManager.shared.outputDevice inputDevice = AudioManager.shared.inputDevice + + // Prepare audio effects + + if let audioUrl = Bundle.main.url(forResource: "tadaa-mono", withExtension: "caf") { + Task { + do { + try soundPlayer.prepare(url: audioUrl, withId: "tadaa") + try await soundPlayer.startEngine() + } catch { + print("Error preparing sound: \(error)") + } + } + } } } diff --git a/Multiplatform/LiveKitExample.swift b/Multiplatform/LiveKitExample.swift index 97dc914..a9644f9 100644 --- a/Multiplatform/LiveKitExample.swift +++ b/Multiplatform/LiveKitExample.swift @@ -16,7 +16,6 @@ import KeychainAccess import LiveKit -import Logging import SwiftUI @MainActor let sync = ValueStore(store: Keychain(service: "io.livekit.example.SwiftSDK.1"), @@ -53,10 +52,6 @@ struct LiveKitExample: App { } init() { - LoggingSystem.bootstrap { - var logHandler = StreamLogHandler.standardOutput(label: $0) - logHandler.logLevel = .debug - return logHandler - } + LiveKitSDK.setLogLevel(.debug) } } diff --git a/Multiplatform/Views/AudioMixerView.swift b/Multiplatform/Views/AudioMixerView.swift index 4d0e028..79308e5 100644 --- a/Multiplatform/Views/AudioMixerView.swift +++ b/Multiplatform/Views/AudioMixerView.swift @@ -30,6 +30,24 @@ struct AudioMixerView: View { Text("App") Slider(value: $appCtx.appVolume, in: 0.0 ... 1.0) } + Button("Play sound effect (Normal)") { + Task { + do { + try await appCtx.playSoundEffectNormal() + } catch { + print("Failed to play sound effect: \(error)") + } + } + } + Button("Play sound effect (API)") { + Task { + do { + try await appCtx.playSoundEffectAPI() + } catch { + print("Failed to play sound effect: \(error)") + } + } + } } } #endif diff --git a/Multiplatform/Views/RoomView.swift b/Multiplatform/Views/RoomView.swift index a430260..69eaa85 100644 --- a/Multiplatform/Views/RoomView.swift +++ b/Multiplatform/Views/RoomView.swift @@ -422,12 +422,11 @@ struct RoomView: View { } label: { Image(systemSymbol: .switch2) } - .disabled(!isMicrophoneEnabled) #if !os(tvOS) - .popover(isPresented: $audioMixerOptionsPresented) { - AudioMixerView() - .padding() - } + .popover(isPresented: $audioMixerOptionsPresented) { + AudioMixerView() + .padding() + } #endif #if os(iOS) diff --git a/Resources/tadaa-mono.caf b/Resources/tadaa-mono.caf new file mode 100644 index 0000000..a3c99b4 --- /dev/null +++ b/Resources/tadaa-mono.caf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9cc4dd9d199cdad23f5aad890a8547bed45be5477eddd990a22fca4d86a8923b +size 34981 diff --git a/Resources/tadaa-stereo.caf b/Resources/tadaa-stereo.caf new file mode 100644 index 0000000..f7e72a5 --- /dev/null +++ b/Resources/tadaa-stereo.caf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0cf3bfe1a8a021d05341e2042cde4dc184d0e69d5eac967b4f6e02a072d9daea +size 35142