Servidor en Kotlin
Importar librerías
io.ktor:ktor-server-netty:1.6.7
io.ktor:ktor-gson:1.6.7
org.slf4j:slf4j-simple:2.0.0-alpha1
org.slf4j:slf4j-simple:1.7.32
Código del servidor
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import java.io.File
fun main() {
val server = embeddedServer(Netty, port = 6000) {
routing {
post("/send-audio") {
val multipart = call.receiveMultipart()
var fileName: String? = null
// Recorre las partes del multipart recibido
multipart.forEachPart { part ->
when (part) {
is PartData.FileItem -> {
fileName = part.originalFileName ?: "audioFile"
val fileBytes = part.streamProvider().readBytes()
// Guarda el archivo en el servidor
writeToFile(fileName!!, fileBytes)
}
else -> { }
}
part.dispose()
}
call.respond(HttpStatusCode.OK, "Archivo de audio guardado: $fileName")
}
}
}
server.start(wait = true)
}
// Función para escribir el archivo de audio
fun writeToFile(fileName: String, fileBytes: ByteArray) {
val file = File(fileName)
file.writeBytes(fileBytes)
}
Cliente en Swift para el Apple Watch que graba un audio y lo envía a un servidor
Cambiar la propiedad Microphone Usage Description (Property List Key NSMicrophoneUsageDescription)
Código para el Apple Watch que graba un audio y lo envía a un servidor
import AVFoundation
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Button(action: {
startRecording()
}) {
Text("Iniciar grabación")
.padding()
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(8)
}
Button(action: {
sendRecordedAudio()
}) {
Text("Enviar grabación")
.padding()
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(8)
}
}
}
func startRecording() {
let audioFilename = getDocumentsDirectory().appendingPathComponent("recording.wav")
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.playAndRecord, mode: .default, options: [])
try audioSession.setActive(true)
let settings: [String: Any] = [
AVFormatIDKey: kAudioFormatLinearPCM,
AVSampleRateKey: 44100.0,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
let audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
audioRecorder.record()
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
audioRecorder.stop()
print("Grabación finalizada")
print("Audio file is stored at: \(audioFilename)")
}
} catch {
print("Error al iniciar la grabación: \(error.localizedDescription)")
}
}
func sendRecordedAudio() {
let audioFilename = getDocumentsDirectory().appendingPathComponent("recording.wav")
guard let audioData = try? Data(contentsOf: audioFilename) else {
print("Error al leer el archivo de audio")
return
}
let url = URL(string: "http://192.168.1.55:6000/send-audio")! // Reemplaza con la URL de tu servidor
var request = URLRequest(url: url)
request.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = Data()
if let boundaryData = "--\(boundary)\r\n".data(using: .utf8),
let dispositionData = "Content-Disposition: form-data; name=\"audioFile\"; filename=\"recording.wav\"\r\n".data(using: .utf8),
let contentTypeData = "Content-Type: audio/wav\r\n\r\n".data(using: .utf8),
let boundaryEndData = "\r\n--\(boundary)--\r\n".data(using: .utf8) {
body.append(boundaryData)
body.append(dispositionData)
body.append(contentTypeData)
body.append(audioData)
body.append(boundaryEndData)
} else {
print("Error al convertir los datos de cadena a Data")
return
}
request.httpBody = body
if let bodySize = request.httpBody?.count {
print("Tamaño aproximado del paquete a enviar: \(bodySize) bytes")
} else {
print("Error al calcular el tamaño del paquete")
}
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error al enviar el archivo de audio: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("Código de estado HTTP: \(httpResponse.statusCode)")
}
}.resume()
}
func getDocumentsDirectory() -> URL {
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
}
}
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Publicado el día 2 de enero de 2024 CATEGORÍAS Kotlin , Swift , Web Service , Xcode