顺便去淘宝霸笔了

      去年有好几次都准备去华科去看看覃博和静仔的,可不是静仔没空就是覃博出差,所以一直拖到今年了。 这次还约了老赵他们几个已经工作了的同学一起去。

      原来计算机六班,在余区这边只剩下我和苏芹了,当然我们两个一起去了。她问我去不去淘宝笔试,淘宝的笔试就在那天,本来我不打算去的,本人虽然技术不才,但意志坚定,除了游戏公司,其它都不感冒。可都跑到光谷那边去玩了,正好那里有笔试,干嘛不去呢?所以我决定去打打酱油!

      大家有差不多一年没有见面了,还是老样子。可这次去发现与以往同学聚会一个很大的不同:除了我,没有单身汉了!   汗……

      覃博和老赵都带着女朋友去的,覃博真能藏的住,静仔和他一个学校,都没见过他女朋友。老赵有女朋友我也是前几天才知道的。

      本来打算和小肖他们一起去武大笔试的,苏芹想去武大看看樱花。可3点笔试开始,2点20我们还在光谷等车,唯一去武大的591迟迟不来。连打的都没有车愿意去武大,那边太堵了。没办法,只能在华科笔试了。

      华科的笔试安排在西十二,这个武汉地区的学生都很熟悉的教学楼。去了后才发现,也许我们来错地方了。笔试名单里一个武汉理工的都没有,至少有五个大教室,95%以上都是华科的,零星有有几个地大的,湖工的……。反正是来霸笔的嘛,名单里没有是正常的。可前面几个教室不仅里面基本座满了,外面还有一大堆在那里等着,估计是我们的同路人。好在我霸笔经验比较丰富(去年随师兄打过两次酱油),选了最后的一个教室,那里面的人果然比前几个少的多。可郁闷的是,淘宝的试卷居然不够,别人开考了近50分钟,我们霸笔的才拿到卷,不过我们后发卷的考试结束时间也延迟了。

       第一大题是8个选择题,每题5分。有数据结构,C语言的,一般不是太难。最难的可能就是问如果用矩形来表示世界各国的地图,用不同颜色区分邻国。问至少要多少种颜色,我不会证明。但记得好像有个四色地图着色问题,地图着色中地图是不规则的,都要4种。那么这里的答案肯定不可能超过4了。答案中好像只有一个少于4的(印象中是那样的),所以猜的就是3种。第二题是填空,不是太难。每空5分,共35分。第三题是大题,每题10分。很奇怪,为什么他们的满分是105? 第一小题是用砝码称大米,不是很清楚出题人的意思。50g和200g的砝码称1350g 大米,最少称几次。我答了两种情况:1)已知重量的大米可以作为砝码使用。2)相反。写到这里,忽然意识到在网上写笔试题貌似不太好。后面就不说具体内容了吧,第二个小题与算法相关,但也不知道有没有一个什么比较有名的算法能解决那个问题。只是根据自己的推测答的,感觉应该可以解决。但我证明不了。第三小题与数据库相关,可能还要有相当的经验才能解决。我实在是太长时间没看数据库了,而且也没有多少时间了,所以就放弃了第三题。反正也是打酱油的嘛!

      也算是今年的第二次笔试了,感快把论文开题搞完,为实习做准备吧!大部分东西都忘了!

<think>我们之前已经完成了Android应用代码的编写,现在需要生成一个Python脚本,用于接收来自Android应用的音频数据并保存为WAV文件。同时,该脚本还可以发送控制指令(如开始录音、停止录音)以及TTS指令。要求:1.使用TCP协议,端口30000(与Android端一致)2.能够接收音频数据包(Base64编码的PCM数据)并实时写入WAV文件3.支持发送控制指令(如开始录音、停止录音)4.支持发送TTS指令,让Android设备播放指定文本我们将编写一个Python脚本,包含以下功能:-连接Android设备(作为TCP客户端)-接收数据并解析(以双换行符作为数据包分隔符)-将接收到的音频数据实时写入WAV文件(每次收到一个数据包就追加写入) -提供简单的命令行界面,允许用户输入控制指令和TTS文本注意:WAV文件需要正确的头,我们将在开始录音时创建WAV文件头,并在停止录音时更新头中的文件大小信息。步骤:1.建立TCP连接2.接收数据并解析JSON3.根据数据类型处理:-如果是音频数据(type:'recording'),则解码Base64并写入文件-如果是控制指令响应,则打印出来4.提供用户输入循环,允许发送指令(如开始录音、停止录音、TTS播放等)由于WAV文件头需要知道整个文件的数据长度,而我们在录音过程中无法预知,所以采用以下方式:-在开始录音时,先写入一个临时的文件头(44字节)-不断追加音频数据-停止录音时,重新计算文件大小,并更新文件头但是,实时写入时,我们每次收到数据就写入,所以需要:-在开始录音时打开文件,写入一个临时的头(44字节,内容全0)-每次收到音频数据,写入文件(注意:数据是PCM16bit,单声道,44100Hz)-停止录音时,将文件指针移到开头,写入正确的头,然后关闭文件我们使用`wave`模块可以简化头信息的写入,但注意:使用wave模块在写入过程中不能动态更新头,所以我们可以:-不使用wave模块,自己管理WAV文件格式-或者,在停止录音后,重新打开文件更新头这里我们选择自己管理WAV文件头,因为需要实时写入。具体WAV文件格式如下:WAV文件头结构(44字节):1.4字节: "RIFF"2.4字节:整个文件大小(不包括前8字节,即文件总字节数-8)3.4字节: "WAVE"4.4字节:"fmt"5.4字节:fmt chunk的大小(16字节)6.2字节:音频格式(1表示PCM)7.2字节:声道数(1)8.4字节:采样率(44100)9.4字节:字节率(采样率 *块对齐)10.2字节:块对齐(声道数*每个样本的字节数,2字节)11.2字节:每个样本的位数(16)12.4字节:"data"13.4字节:数据部分的大小(即PCM数据的字节数)因此,我们可以在开始录音时先写入44字节的占位,然后不断追加数据。停止录音后,再更新第2字节开始的4字节(整个文件大小-8)和第40字节开始的4字节(数据大小)。但是,由于我们是在同一台机器上运行,且文件写入是顺序的,我们可以:-先写入44字节的0(作为占位)-写入音频数据-最后更新头然而,如果程序意外终止,文件头可能不会更新,导致文件损坏。因此,我们也可以选择在停止录音后,再写入文件头。但这样就不能实时保存了。所以这里我们选择先占位,最后更新。具体步骤:1.当收到开始录音指令(或者用户输入开始录音)时,我们打开一个文件,写入44字节的0(或者一个临时的头,但数据大小未知,所以先写0)。2.每次收到音频数据,就写入文件。3.当收到停止录音指令(或用户输入停止录音)时,我们计算整个文件大小和数据大小,然后更新文件头。注意:文件总大小 =44+音频数据字节数数据大小=音频数据字节数因此,更新头:-位置0:写入"RIFF"-位置4:写入文件总大小-8(即36+音频数据字节数,因为文件总大小=44+音频数据字节数,所以文件总大小-8=36+音频数据字节数)-位置40:写入音频数据字节数但是,我们也可以使用更规范的方式:按照上述结构写入。下面,我们将编写一个Python脚本,实现上述功能。代码结构:-建立TCP连接-启动一个线程用于接收数据-主线程提供用户输入-接收线程处理数据包并写入文件注意:由于网络数据流可能包含多个数据包,我们使用双换行符("\n\n")作为分隔符。我们将定义以下函数:- write_wav_header(f, file_size,data_size):用于在文件开头写入正确的头(在停止录音时调用)-或者,在开始录音时写一个空头,停止录音时再更新。实现:步骤:1.连接服务器(Android设备)2.发送控制指令(如果需要)3.接收数据,解析数据包(以双换行符分割)4.解析JSON5.根据类型处理由于我们可能同时需要接收和发送,所以接收数据使用单独线程。下面给出完整代码:</think>下面是一个完整的Python脚本,用于接收Android应用发送的音频数据并保存为WAV文件。这个脚本还支持发送控制指令给Android设备: ```python import socket import json import base64 import threading import wave import sys import os from datetime import datetime class AudioReceiver: def __init__(self, host='0.0.0.0', port=30000): self.host = host self.port = port self.server_socket = None self.client_socket = None self.is_running = False self.recording = False self.wav_file = None self.output_dir = "recordings" # 创建输出目录 os.makedirs(self.output_dir, exist_ok=True) def start_server(self): """启动TCP服务器""" self.is_running = True try: self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.bind((self.host, self.port)) self.server_socket.listen(1) print(f"服务器启动,监听端口 {self.port}") # 接受客户端连接 self.client_socket, addr = self.server_socket.accept() print(f"客户端已连接: {addr[0]}:{addr[1]}") # 启动接收线程 threading.Thread(target=self.receive_data, daemon=True).start() # 启动命令输入线程 threading.Thread(target=self.command_interface, daemon=True).start() except Exception as e: print(f"服务器启动失败: {e}") self.stop_server() def receive_data(self): """接收并处理数据""" buffer = b'' try: while self.is_running and self.client_socket: # 接收数据 data = self.client_socket.recv(4096) if not data: print("客户端断开连接") break buffer += data # 处理完整的数据包 (以双换行符分隔) while b'\n\n' in buffer: packet, buffer = buffer.split(b'\n\n', 1) try: # 解析JSON数据包 json_str = packet.decode('utf-8').strip() if not json_str: continue packet_data = json.loads(json_str) packet_type = packet_data.get('type') packet_content = packet_data.get('data') # 处理不同类型的包 if packet_type == 'recording': self.handle_audio_data(packet_content) elif packet_type == 'control': print(f"控制指令: {packet_content}") elif packet_type == 'response': print(f"设备响应: {packet_content}") else: print(f"未知数据包类型: {packet_type}") except (json.JSONDecodeError, UnicodeDecodeError) as e: print(f"数据包解析错误: {e}") print(f"原始数据: {packet}") except Exception as e: print(f"接收数据错误: {e}") finally: self.stop_recording() self.stop_server() def handle_audio_data(self, audio_b64): """处理音频数据""" if not self.recording: return try: # 解码Base64音频数据 audio_data = base64.b64decode(audio_b64) # 写入WAV文件 self.wav_file.writeframes(audio_data) print(f"接收音频数据: {len(audio_data)}字节", end='\r') except Exception as e: print(f"处理音频数据错误: {e}") def start_recording(self): """开始录音""" if self.recording: print("已经在录音中") return # 创建新的WAV文件 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = os.path.join(self.output_dir, f"recording_{timestamp}.wav") try: self.wav_file = wave.open(filename, 'wb') self.wav_file.setnchannels(1) # 单声道 self.wav_file.setsampwidth(2) # 16位 = 2字节 self.wav_file.setframerate(44100) # 44.1kHz采样率 print(f"开始录音: {filename}") self.recording = True # 发送开始录音指令 self.send_control("start_recording") except Exception as e: print(f"创建WAV文件失败: {e}") self.wav_file = None def stop_recording(self): """停止录音""" if not self.recording: return self.recording = False # 关闭WAV文件 if self.wav_file: self.wav_file.close() self.wav_file = None print("\n录音已停止") # 发送停止录音指令 self.send_control("stop_recording") def send_control(self, command): """发送控制指令""" if not self.client_socket: print("客户端未连接,无法发送指令") return try: # 创建控制包 packet = { "type": "control", "data": command } json_str = json.dumps(packet) + "\n\n" # 发送数据 self.client_socket.sendall(json_str.encode('utf-8')) print(f"已发送指令: {command}") except Exception as e: print(f"发送控制指令失败: {e}") def send_tts(self, text): """发送TTS指令""" if not self.client_socket: print("客户端未连接,无法发送指令") return try: # 创建TTS包 packet = { "type": "tts_speak", "data": text } json_str = json.dumps(packet) + "\n\n" # 发送数据 self.client_socket.sendall(json_str.encode('utf-8')) print(f"已发送TTS指令: {text}") except Exception as e: print(f"发送TTS指令失败: {e}") def command_interface(self): """命令输入界面""" print("\n命令帮助:") print(" start - 开始录音") print(" stop - 停止录音") print(" tts [文本] - 发送TTS文本") print(" exit - 退出程序") while self.is_running: try: cmd = input("\n> ").strip().lower() if cmd == "start": self.start_recording() elif cmd == "stop": self.stop_recording() elif cmd.startswith("tts"): text = cmd[3:].strip() if text: self.send_tts(text) else: print("请输入TTS文本") elif cmd == "exit": print("退出程序...") self.stop_server() break else: print("未知命令") except KeyboardInterrupt: print("\n退出程序...") self.stop_server() break except Exception as e: print(f"命令处理错误: {e}") def stop_server(self): """停止服务器""" self.is_running = False self.stop_recording() # 关闭客户端连接 if self.client_socket: try: self.client_socket.close() except: pass self.client_socket = None # 关闭服务器套接字 if self.server_socket: try: self.server_socket.close() except: pass self.server_socket = None print("服务器已停止") if __name__ == "__main__": # 获取命令行参数 host = '0.0.0.0' port = 30000 if len(sys.argv) > 1: host = sys.argv[1] if len(sys.argv) > 2: try: port = int(sys.argv[2]) except ValueError: print("端口号必须是整数") sys.exit(1) # 启动接收器 receiver = AudioReceiver(host, port) receiver.start_server() ``` ### 脚本功能详解 1. **TCP服务器实现** - 监听指定端口(默认30000) - 接受Android设备的连接 - 使用双换行符(`\n\n`)作为数据包分隔符 2. **音频数据处理** - 接收Base64编码的PCM音频数据 - 解码并保存为WAV文件 - 自动生成带时间戳的文件名 3. **控制指令系统** - `start`:发送开始录音指令 - `stop`:发送停止录音指令 - `tts [文本]`:发送TTS文本让Android设备播放 - `exit`:退出程序 4. **WAV文件管理** - 使用Python `wave`模块处理音频文件 - 设置正确的音频参数(单声道, 16位, 44.1kHz) - 录音文件保存在`recordings`目录下 ### 使用说明 1. **启动脚本** ```bash python audio_receiver.py [IP地址] [端口] ``` 默认监听所有IP地址(`0.0.0.0`)和端口`30000` 2. **基本操作** - 启动后等待Android设备连接 - 输入`start`开始录音 - 输入`stop`停止录音 - 输入`tts 你好世界`让Android设备播放TTS - 输入`exit`退出程序 3. **文件保存** - 录音文件保存在`recordings`目录 - 文件名格式:`recording_YYYYMMDD_HHMMSS.wav` ### 技术细节 1. **数据包格式** ```json { "type": "recording", "data": "Base64编码的PCM数据" } ``` 2. **控制指令格式** ```json { "type": "control", "data": "start_recording" // 或 "stop_recording" } ``` 3. **TTS指令格式** ```json { "type": "tts_speak", "data": "要播放的文本" } ``` 4. **音频文件格式** - 格式: WAV - 编码: PCM - 声道: 单声道 - 采样率: 44100 Hz - 位深: 16位 ### 与Android应用的配合 1. Android应用启动TCP服务器 2. Python脚本连接Android设备 3. 通过脚本发送控制指令 4. Android设备发送音频数据 5. 脚本保存为WAV文件 ### 注意事项 1. **防火墙设置** - 确保Android设备和运行脚本的电脑在同一个网络 - 允许TCP端口30000的通信 2. **Android设备IP** - 脚本需要连接Android设备的IP地址 - 可以在Android设置中查看设备IP 3. **实时性** - 脚本会实时写入接收到的音频数据 - 停止录音时会正确关闭WAV文件头
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值