attempt to fix mic audio streaming
This commit is contained in:
Binary file not shown.
+101
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: UTF-8 -*-
|
||||
"""
|
||||
Standalone NAO audio diagnostic - deliberately bypasses naowalk.py entirely.
|
||||
|
||||
Run this FIRST when troubleshooting "I can't hear the robot's mic". It tests
|
||||
each link in the chain independently, so a failure tells you exactly where
|
||||
the problem is instead of "somewhere in 300 lines of PyAudio/threading code":
|
||||
|
||||
TEST 1 - Front mic hardware energy.
|
||||
Uses ALAudioDevice's built-in energy meter. No PyAudio, no
|
||||
network audio streaming, no laptop audio stack involved at all.
|
||||
This is the lowest-level check of "does the mic itself work".
|
||||
|
||||
TEST 2 - Local on-robot recording.
|
||||
Records straight to a .wav file on the robot's own disk, then
|
||||
you pull it off and play it normally. This bypasses the live
|
||||
network stream, the SoundReceiver/queue/threading code, and
|
||||
your laptop's PyAudio output path - all at once.
|
||||
|
||||
TEST 3 - Robot's own speaker.
|
||||
Plays a tone through the ROBOT's speaker (not your laptop), to
|
||||
confirm robot-side audio output is fine, independent of any of
|
||||
the mic-listening code.
|
||||
|
||||
If TEST 1 shows no energy change when you make noise: mic hardware/mute/
|
||||
environment issue, upstream of any code in this project.
|
||||
If TEST 1 works but TEST 2's file is silent: something is wrong with the
|
||||
recording/robot-audio-stack itself, still nothing to do with naowalk.py.
|
||||
If TEST 2's file has clear audio: the mic and robot are fine, and the bug
|
||||
is specifically in naowalk.py's live-streaming path (network delivery,
|
||||
PyAudio device selection, etc.) - go back to the diagnostics already
|
||||
built into naowalk.py (device list / test beep / peak level) to isolate it
|
||||
further.
|
||||
|
||||
Usage:
|
||||
python3 nao_audio_diagnostic.py --ip spike.local --port 9559
|
||||
"""
|
||||
|
||||
import qi
|
||||
import argparse
|
||||
import time
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--ip", type=str, default="127.0.0.1")
|
||||
parser.add_argument("--port", type=int, default=9559)
|
||||
args = parser.parse_args()
|
||||
|
||||
session = qi.Session()
|
||||
session.connect(f"tcp://{args.ip}:{args.port}")
|
||||
print(f"✅ Connected to {args.ip}")
|
||||
audio = session.service("ALAudioDevice")
|
||||
|
||||
# --- TEST 1: mic hardware energy, all four channels ------------------------
|
||||
print("\n=== TEST 1: Mic hardware energy (all 4 mics) ===")
|
||||
print("Make noise near the robot's head (clap, talk right up close to it) for 10s...")
|
||||
audio.enableEnergyComputation()
|
||||
front_readings, rear_readings, left_readings, right_readings = [], [], [], []
|
||||
for i in range(10):
|
||||
f, r, l, rt = (audio.getFrontMicEnergy(), audio.getRearMicEnergy(),
|
||||
audio.getLeftMicEnergy(), audio.getRightMicEnergy())
|
||||
front_readings.append(f); rear_readings.append(r); left_readings.append(l); right_readings.append(rt)
|
||||
print(f" t={i}s front={f:.2f} rear={r:.2f} left={l:.2f} right={rt:.2f}")
|
||||
time.sleep(1)
|
||||
audio.disableEnergyComputation()
|
||||
|
||||
results = {"front": front_readings, "rear": rear_readings, "left": left_readings, "right": right_readings}
|
||||
flat = [name for name, vals in results.items() if max(vals) - min(vals) < 2]
|
||||
if len(flat) == 4:
|
||||
print("⚠️ ALL FOUR mics are flat. This points to something systemic - e.g. audio "
|
||||
"inputs closed (closeAudioInputs() called somewhere and never reopened), "
|
||||
"or a low-level hardware/driver fault - rather than one damaged mic.")
|
||||
elif flat:
|
||||
print(f"⚠️ Flat mic(s): {', '.join(flat)}. The others responded normally, which "
|
||||
f"points to a fault specific to {', '.join(flat)} rather than the audio "
|
||||
f"pipeline as a whole (that pipeline is clearly working for the others).")
|
||||
else:
|
||||
print("✅ All four mics responded to noise - hardware capture is fine across the board.")
|
||||
|
||||
# --- TEST 2: local on-robot recording ---------------------------------------
|
||||
print("\n=== TEST 2: Local on-robot recording ===")
|
||||
remote_path = "/home/nao/mic_test.wav"
|
||||
print(f"Recording 5s directly to {remote_path} on the robot itself "
|
||||
f"(this bypasses the network stream and your laptop's audio stack entirely)...")
|
||||
audio.startMicrophonesRecording(remote_path)
|
||||
time.sleep(5)
|
||||
audio.stopMicrophonesRecording()
|
||||
print(f"Done. Pull it off and play it with:")
|
||||
print(f" scp nao@{args.ip}:{remote_path} .")
|
||||
print(f" (then open mic_test.wav in any media player - it's 4-channel, so check all channels)")
|
||||
print("If that file has clearly audible sound, the mic and robot are fine and the")
|
||||
print("bug is specifically in naowalk.py's live-streaming path.")
|
||||
|
||||
# --- TEST 3: robot's own speaker, via TTS (version-agnostic) ---------------
|
||||
print("\n=== TEST 3: Robot's own speaker ===")
|
||||
input("Press Enter to have the robot say a test phrase out loud...")
|
||||
session.service("ALTextToSpeech").say("Testing 1 2 3, can you hear me.")
|
||||
print("If you heard the robot speak just now, its speaker output is fine "
|
||||
"(this is unrelated to hearing its mic on your laptop, but rules out a robot-wide audio fault).")
|
||||
|
||||
print("\nDone. Report back which test(s) failed and we'll know exactly where to look.")
|
||||
+17
-6
@@ -178,7 +178,7 @@ class SoundReceiver:
|
||||
# MAIN TELEOP CLASS
|
||||
# ==========================================
|
||||
class NaoTeleop:
|
||||
def __init__(self, session, audio_device_index=None):
|
||||
def __init__(self, session, audio_device_index=None, mic_channel=1):
|
||||
self.session = session
|
||||
self.motion = session.service("ALMotion")
|
||||
self.posture = session.service("ALRobotPosture")
|
||||
@@ -196,6 +196,7 @@ class NaoTeleop:
|
||||
self.audio_device = None
|
||||
self.audio_service_name = "SoundReceiver"
|
||||
self.audio_device_index = audio_device_index # which laptop output device to play the mic feed on
|
||||
self.mic_channel = mic_channel # which NAO mic to stream: LEFTCHANNEL(1)/RIGHTCHANNEL(2)/FRONTCHANNEL(3)/REARCHANNEL(4)
|
||||
|
||||
self.running = True
|
||||
self.head_yaw = 0.0
|
||||
@@ -261,10 +262,13 @@ class NaoTeleop:
|
||||
# 2. Add a tiny delay to let the network handshake complete
|
||||
time.sleep(0.5)
|
||||
|
||||
# 3. Use the IP of the machine running the code
|
||||
# We explicitly tell the robot the IP of your laptop (replace with your laptop IP if still failing)
|
||||
# '0' tells it to auto-discover, but sometimes we need to be explicit.
|
||||
self.audio_device.setClientPreferences(self.audio_service_name, 16000, 3, 0)
|
||||
# 3. Which physical mic to stream. FRONTCHANNEL(3) was the
|
||||
# original default, but on this robot the front and rear mics
|
||||
# test dead (flat energy readings even up close) while left
|
||||
# and right respond normally - see nao_audio_diagnostic.py.
|
||||
# Defaulting to LEFTCHANNEL(1) accordingly; override with
|
||||
# --mic-channel if you want to compare.
|
||||
self.audio_device.setClientPreferences(self.audio_service_name, 16000, self.mic_channel, 0)
|
||||
self.audio_device.subscribe(self.audio_service_name)
|
||||
|
||||
print("✅ Live Audio Stream ready")
|
||||
@@ -479,6 +483,8 @@ class NaoTeleop:
|
||||
pygame.quit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
MIC_CHANNELS = {"left": 1, "right": 2, "front": 3, "rear": 4}
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--ip", type=str, default="127.0.0.1")
|
||||
parser.add_argument("--port", type=int, default=9559)
|
||||
@@ -486,6 +492,10 @@ if __name__ == "__main__":
|
||||
help="Force a specific PyAudio output device index for the robot's "
|
||||
"mic feed (see the '🔈 Available output devices' list printed "
|
||||
"at startup) if the system default isn't your speakers.")
|
||||
parser.add_argument("--mic-channel", choices=MIC_CHANNELS.keys(), default="left",
|
||||
help="Which NAO mic to stream. Defaults to 'left' since "
|
||||
"nao_audio_diagnostic.py confirmed front/rear are dead on "
|
||||
"this unit while left/right respond normally.")
|
||||
args = parser.parse_args()
|
||||
|
||||
session = qi.Session()
|
||||
@@ -496,4 +506,5 @@ if __name__ == "__main__":
|
||||
print(f"❌ Connection failed: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
NaoTeleop(session, audio_device_index=args.audio_device_index).run()
|
||||
NaoTeleop(session, audio_device_index=args.audio_device_index,
|
||||
mic_channel=MIC_CHANNELS[args.mic_channel]).run()
|
||||
|
||||
Reference in New Issue
Block a user