import io.github.jaredmdobson.concentus.OpusApplication import io.github.jaredmdobson.concentus.OpusDecoder import io.github.jaredmdobson.concentus.OpusEncoder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import java.io.IOException import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.io.Serializable import java.net.InetSocketAddress import java.net.Socket import javax.sound.sampled.AudioSystem import kotlin.system.measureTimeMillis class Client { companion object { @JvmStatic fun main(args: Array) { Client().mainClient() } } val bufferOut = ByteArray(BUFFER_SIZE) val targetDataLine = AudioSystem.getTargetDataLine(AUDIO_FORMAT).also { it.open(AUDIO_FORMAT, bufferOut.size) it.start() } val bufferIn = ByteArray(BUFFER_SIZE) val sourceDataLine = AudioSystem.getSourceDataLine(AUDIO_FORMAT).also { it.open(AUDIO_FORMAT, bufferIn.size) it.start() } val decoder = OpusDecoder(SAMPLE_RATE, CHANNELS) val encoder = OpusEncoder(SAMPLE_RATE, CHANNELS, OpusApplication.OPUS_APPLICATION_AUDIO).also { it.bitrate = OPUS_BITRATE it.forceMode = OPUS_MODE it.signalType = OPUS_SIGNAL_TYPE it.complexity = OPUS_COMPLEXITY } fun mainClient() { val socket = Socket() val scope = CoroutineScope(Dispatchers.IO) val t = measureTimeMillis { socket.connect(InetSocketAddress(SERVER_HOST, SERVER_PORT)) } "connect time $t".loge() val out = ObjectOutputStream(socket.getOutputStream()) val inp = ObjectInputStream(socket.getInputStream()) val recordJob = scope.launch { while (true) { targetDataLine.read(bufferOut, 0, bufferOut.size) try { out.writeObject(encoder.encode(bufferOut)) out.flush() } catch (e: Exception) { e.printStackTrace() System.exit(0) } } } val playJob = scope.launch { while (true) { try { // if (`in`!!.available() > bufferIn.size * 2) { // `in`!!.skip(`in`!!.available().toLong() - bufferIn.size) // println("丢弃") // } // `in`!!.read(bufferIn, 0, bufferIn.size) val dataPack = inp.readObject() as DataPack decoder.decode(dataPack, bufferIn) sourceDataLine.write(bufferIn, 0, bufferIn.size) } catch (e: IOException) { e.printStackTrace() System.exit(0) } } } runBlocking { recordJob.join() playJob.join() } } }