Android录制音频发送至服务器后文件过小问题求助
Android AudioRecord录制音频发送至Python服务器仅收到极小文件的解决方案
核心问题分析
你的代码里最大的问题是录制逻辑错误:
- 调用
audioRecord.stop()后才尝试读取音频数据,此时AudioRecord已经停止工作,内部缓冲区的音频数据无法被完整读取。 - 只执行了一次
audioRecord.read(),没有在录制过程中持续采集数据,所以只能拿到单次缓冲区大小的数据(也就是你看到的约2KB)。
Android端代码修复
1. 重构录制逻辑,在录制过程中持续读取数据
需要在startRecording时启动协程,不断从AudioRecord读取数据并缓存,停止录制时再停止读取并发送缓存的完整数据。
修改后的MediaRecorder类:
class MediaRecorder(app: Application) { private val bufferSize: Int private lateinit var audioRecord: AudioRecord private val sampleRate: Int = 16000 private val channelConfig: Int = AudioFormat.CHANNEL_IN_MONO private val audioFormat: Int = AudioFormat.ENCODING_PCM_16BIT private val app: Application = app private var isRecording = false private val recordedData = ByteArrayOutputStream() // 缓存所有录制的音频数据 init { bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) * 4 } fun startRecording() { if (ActivityCompat.checkSelfPermission( app.applicationContext, Manifest.permission.RECORD_AUDIO ) != PackageManager.PERMISSION_GRANTED ) { return // 建议补充权限申请逻辑,避免无权限时崩溃 } audioRecord = AudioRecord( MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, bufferSize ) audioRecord.startRecording() isRecording = true // 启动协程持续读取音频数据 CoroutineScope(Dispatchers.IO).launch { val buffer = ByteArray(bufferSize) while (isRecording) { val bytesRead = audioRecord.read(buffer, 0, bufferSize) if (bytesRead > 0) { recordedData.write(buffer, 0, bytesRead) // 仅写入实际读取到的字节 } } } } fun stopRecording() { isRecording = false audioRecord.stop() audioRecord.release() val fullAudioData = recordedData.toByteArray() Log.i("Audio", "Total recorded bytes: ${fullAudioData.size}") if (fullAudioData.isNotEmpty()) { sendByteArrayToServer(fullAudioData) } else { Log.e("Audio", "No audio data recorded.") } recordedData.reset() // 重置缓冲区,方便下次录制 } }
2. 发送代码优化(可选)
当前发送逻辑可用,但添加数据长度标识后,服务器可以精准接收完整数据,避免提前终止:
fun sendByteArrayToServer(byteArray: ByteArray) { CoroutineScope(Dispatchers.IO).launch { try { val serverAddress = "your_ip_here" val serverPort = 9999 val socket = Socket(serverAddress, serverPort) val outputStream = socket.getOutputStream() val dataOutputStream = DataOutputStream(outputStream) // 先发送数据总长度,让服务器明确接收目标 dataOutputStream.writeInt(byteArray.size) dataOutputStream.write(byteArray) dataOutputStream.flush() Log.i("Server", "Byte array sent successfully, total bytes: ${byteArray.size}") socket.close() } catch (e: Exception) { e.printStackTrace() Log.e("Server", "Error sending byte array to server: ${e.message}") } } }
Python服务器代码适配(对应发送端的长度标识优化)
如果修改了发送端添加长度标识,服务器需要先读取长度,再接收对应字节的数据:
import socket host = '0.0.0.0' port = 9999 sample_rate = 16000 channels = 1 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((host, port)) server_socket.listen(1) print(f"Server listening on port {port}") while True: client_socket, client_address = server_socket.accept() print(f"Accepted connection from {client_address}") audio_file = open("received_audio.pcm", "wb") try: # 先读取4字节的数据长度(对应Java的int类型) length_data = client_socket.recv(4) if not length_data: print("No length data received") continue total_length = int.from_bytes(length_data, byteorder='big') print(f"Expecting {total_length} bytes of audio data") received_bytes = 0 while received_bytes < total_length: # 每次读取不超过剩余需要接收的字节数 chunk_size = min(1024, total_length - received_bytes) data = client_socket.recv(chunk_size) if not data: break audio_file.write(data) received_bytes += len(data) print(f"Received {received_bytes}/{total_length} bytes") except Exception as e: print(f"Error receiving data: {e}") finally: audio_file.close() client_socket.close() print("PCM audio data received and saved as 'received_audio.pcm'")
额外注意事项
- 确保Android端已申请
RECORD_AUDIO和INTERNET权限,且运行时获取了录音权限。 - 可先将录制的PCM数据保存到本地,验证数据长度是否正常,再排查网络发送问题。
- PCM为原始音频数据,需用Audacity等工具打开,并设置对应采样率、位深和通道数才能正常播放。
内容的提问来源于stack exchange,提问作者Pulsarr
相关产品推荐
相关产品推荐

