Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Level Networking on watchOS for Duplex audio streaming

I did watch WWDC 2019 Session 716 and understand that an active audio session is key to unlocking low‑level networking on watchOS. I’m configuring my audio session and engine as follows:

		private func configureAudioSession(completion: @escaping (Bool) -> Void) {
		    let audioSession = AVAudioSession.sharedInstance()
		    do {
		        try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: [])
		        try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
		        // Retrieve sample rate and configure the audio format.
		        let sampleRate = audioSession.sampleRate
		        print("Active hardware sample rate: \(sampleRate)")
		        audioFormat = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: 1)
		        // Configure the audio engine.
		        audioInputNode = audioEngine.inputNode
		        audioEngine.attach(audioPlayerNode)
		        audioEngine.connect(audioPlayerNode, to: audioEngine.mainMixerNode, format: audioFormat)
		        
		        try audioEngine.start()
		        completion(true)
		    } catch {
		        print("Error configuring audio session: \(error.localizedDescription)")
		        completion(false)
		    }
		}
		 
		private func setupUDPConnection() {
		    let parameters = NWParameters.udp
		    parameters.includePeerToPeer = true
		    connection = NWConnection(host: "***.***.xxxxx.***", port: 0000, using: parameters)
		    setupNWConnectionHandlers()
		}
		 
		   
		    private func setupTCPConnection() {
		        let parameters = NWParameters.tcp
		        connection = NWConnection(host: "***.***.xxxxx.***", port: 0000, using: parameters)
		        setupNWConnectionHandlers()
		    }
		 
		    
		    private func setupWebSocketConnection() {
		        guard let url = URL(string: "ws://***.***.xxxxx.***:0000") else {
		            print("Invalid WebSocket URL")
		            return
		        }
		 
		        let session = URLSession(configuration: .default)
		        webSocketTask = session.webSocketTask(with: url)
		        webSocketTask?.resume()
		        print("WebSocket connection initiated")
		        sendAudioToServer()
		        receiveDataFromServer()
		        sendWebSocketPing(after: 0.6)
		    }
		 
		    private func setupNWConnectionHandlers() {
		        connection?.stateUpdateHandler = { [weak self] state in
		            DispatchQueue.main.async {
		                switch state {
		                case .ready:
		                    print("Connected (NWConnection)")
		                    self?.isConnected = true
		                    self?.failToConnect = false
		                    self?.receiveDataFromServer()
		                    self?.sendAudioToServer()
		                case .waiting(let error), .failed(let error):
		 
		                    print("Connection error: \(error.localizedDescription)")
		                    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
		                        self?.setupNetwork()
		                    }
		                case .cancelled:
		                    print("NWConnection cancelled")
		                    self?.isConnected = false
		 
		                default:
		                    break
		                }
		            }
		        }
		        connection?.start(queue: .main)
		    }
		 
	 

Duplex in this context refers to two-way audio transmission simultaneously recording and sending audio while also receiving and playing back incoming audio, similar to a VoIP/SIP call.

The setup works fine on the simulator, which suggests that the core logic is correct. However, since the simulator doesn’t fully replicate WatchOS hardware behavior especially for audio sessions and networking issues might arise when running on a real device.

The problem likely lies in either the Watch’s actual hardware limitations, permission constraints, or specific audio session configurations.

I am reaching out to seek further assistance regarding the challenges I've been experiencing with establishing a UDP, TCP & web socket connection on watchOS using NWConnection for duplex audio streaming. Despite implementing the recommendations provided earlier, I am still encountering difficulties

From what I can see, your implementation is focused on streaming audio playback with the server. In my case, I'm looking for a slightly different approach: I want to capture audio and send buffers of a specific size to the server while playing audio simultaneously, essentially achieving full duplex streaming similar to a VOIP call. Additionally, I’d like to ensure that if no external audio route is connected, the Apple Watch speaker is used by default. Any thoughts or insights on adapting this setup for those requirements would be very welcome.

Any update ?

Level Networking on watchOS for Duplex audio streaming
 
 
Q