About flow between send and receive in Network.framework

Hi, I'm trying to build a Walki-talkie app using Swift.

My Idea is...

  1. record user's voice by AVAudioEngine in device1
  2. convert recorded file into Data type data
  3. send data from device1 to device2 using NWConnection.send
  4. receive data using NWConnection.receiveMessage
  5. play received data in device2

I am implementing this app using P2P option in Network.framework, so each device has both browser and listener.

And I have to make each device to keep receiving incoming data, and to send recorded voices.

At first I thought that if receiveMessage method was executed, it would wait for other device's send method to send data and receive it.

But while debugging, program didn't stopped at receiveMessage method, it just went through and executed next line.

I must be missing something, but I'm not sure what it is.

Below is send and receive part of code I tried.

    func sendRecordedAudio(data: Data) {

        guard let connection = connection else {

            print("connection optional unwrap failed: sendRecordedAudio")

            return
        }

        connection.send(content: data, completion: .contentProcessed({ (error) in

            if let error = error {

                print("Send error: \(error)")

            }
        }))
    }


    func receiveRecordedAudio() {        

        guard let connection = connection else {

            print("connection optional unwrap failed: receiveRecordedAudio")

            return

        }

        connection.receiveMessage{ (data, context, isComplete, error) in

            if let error = error {

                print("\(error) occurred in receiveRecordedAudio")

            }

            if let data = data {

                self.delegate?.receivedAudio(data: data)

            }
        }
    }

App is calling sendRecordAudio when recording audio is ended, and calling receiveRecordeAudio when user pressed receive button.

Any help would be greatly appreciated!

Accepted Reply

But while debugging, program didn't stopped at receiveMessage method, it just went through and executed next line.

I suspect that receiveRecordedAudio is being executed, but only once. For your connection to keep receiving data you will need to create a receive loop. For example:

func receiveRecordedAudio() {        

    guard let connection = connection else {
        print("connection optional unwrap failed: receiveRecordedAudio")
        return

    }

    connection.receiveMessage{ (data, context, isComplete, error) in

    	// Receive data and mark a local variable that data is received.
    	var dataLen = 0
    	if let incomingData = data {
    		// Do something with the data
    		dataLen = incomingData.count
    	}
    	// Check for errors. If there are error, cancel the connection.
    	if err = error {
    		connection.cancel()
    	}

    	// If `isComplete` is false and there was data received on the connection:
    	if !isComplete, dataLen > 0 {
    		self.receiveRecordedAudio() // I suspect this is your issue
    	} else {
    		connection.cancel() // Possibly EOF??
    	}
    }
}

Also, I am not sure the specifics on your project but there may be other options for doing a push to talk, or walkie talkie style app. See this thread if it applies.

  • Thank you very much! My problem was solved by adopting receive loop.

    I only thought about using while Loop, but this is far more clean and reasonable way to implement a receive loop.

    I also called receiveRecordedAudio when connection state is ready to set application to receive any incoming data from other device.

    Thank you again! 😁

  • No problem at all. Glad to help.

Add a Comment

Replies

But while debugging, program didn't stopped at receiveMessage method, it just went through and executed next line.

I suspect that receiveRecordedAudio is being executed, but only once. For your connection to keep receiving data you will need to create a receive loop. For example:

func receiveRecordedAudio() {        

    guard let connection = connection else {
        print("connection optional unwrap failed: receiveRecordedAudio")
        return

    }

    connection.receiveMessage{ (data, context, isComplete, error) in

    	// Receive data and mark a local variable that data is received.
    	var dataLen = 0
    	if let incomingData = data {
    		// Do something with the data
    		dataLen = incomingData.count
    	}
    	// Check for errors. If there are error, cancel the connection.
    	if err = error {
    		connection.cancel()
    	}

    	// If `isComplete` is false and there was data received on the connection:
    	if !isComplete, dataLen > 0 {
    		self.receiveRecordedAudio() // I suspect this is your issue
    	} else {
    		connection.cancel() // Possibly EOF??
    	}
    }
}

Also, I am not sure the specifics on your project but there may be other options for doing a push to talk, or walkie talkie style app. See this thread if it applies.

  • Thank you very much! My problem was solved by adopting receive loop.

    I only thought about using while Loop, but this is far more clean and reasonable way to implement a receive loop.

    I also called receiveRecordedAudio when connection state is ready to set application to receive any incoming data from other device.

    Thank you again! 😁

  • No problem at all. Glad to help.

Add a Comment