In my swift code I have opened a websocket connection with eleven labs and am sending it text and getting back chunks of audio data in stream that I want to play continuously and start the playback as soon as the first chunk arrives.
But it only plays a very small part of the text and then stops abruptly and I see the error :
WebSocket receive error: Error Domain=NSPOSIXErrorDomain Code=57 “Socket is not connected”
Audio player error: Error Domain=NSOSStatusErrorDomain Code=1954115647 “(null)”
My code is :
class WebSocketViewModel: NSObject, ObservableObject, URLSessionWebSocketDelegate {
private var webSocketTask: URLSessionWebSocketTask?
private var player: AVAudioPlayer?
private var audioBuffer = Data()
func connectAndPlay() {
let urlString = "wss://api.elevenlabs.io/v1/text-to-speech/voice-id/stream-input?model_id=eleven_turbo_v2"
guard let url = URL(string: urlString) else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
let session = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
webSocketTask = session.webSocketTask(with: request)
webSocketTask?.resume()
sendInitialMessages(apiKey: apiKey)
}
private func sendInitialMessages(apiKey: String) {
let bosMessage: [String: Any] = [
"text": " ",
"voice_settings": [
"stability": 0.5,
"similarity_boost": 0.8
],
"xi_api_key": apiKey
]
sendMessage(bosMessage)
let textMessage: [String: Any] = [
"text": "Hello World this is just a random message for testing purposes",
]
sendMessage(textMessage)
let eosMessage: [String: Any] = [
"text": ""
]
sendMessage(eosMessage)
}
private func sendMessage(_ message: [String: Any]) {
do {
let messageData = try JSONSerialization.data(withJSONObject: message, options: [])
let messageString = String(data: messageData, encoding: .utf8) ?? ""
let webSocketMessage = URLSessionWebSocketTask.Message.string(messageString)
webSocketTask?.send(webSocketMessage) { error in
if let error = error {
print("WebSocket send error: (error)")
}
}
} catch {
print("JSON serialization error: (error)")
}
}
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
print("WebSocket connection opened")
receiveMessages()
}
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
print("WebSocket connection closed")
}
private func receiveMessages() {
webSocketTask?.receive { [weak self] result in
switch result {
case .failure(let error):
print("WebSocket receive error: (error)")
case .success(let message):
switch message {
case .string(let text):
self?.handleMessage(text)
default:
break
}
self?.receiveMessages()
}
}
}
private func handleMessage(_ text: String) {
guard let data = text.data(using: .utf8),
let response = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { return }
if let audioBase64 = response["audio"] as? String {
addToAudioBuffer(audioBase64)
if player == nil || !player!.isPlaying {
playAudio()
}
}
if let isFinal = response["isFinal"] as? Bool, isFinal {
print("Audio generation is complete.")
}
}
private func addToAudioBuffer(_ base64String: String) {
guard let audioData = Data(base64Encoded: base64String) else {
print("Failed to decode base64 audio data")
return
}
audioBuffer.append(audioData)
}
private func playAudio() {
guard !audioBuffer.isEmpty else {
print("Audio buffer is empty")
return
}
do {
player = try AVAudioPlayer(data: audioBuffer)
player?.play()
} catch {
print("Audio player error: (error)")
}
audioBuffer.removeAll()
}
}