Hi,
Is this module compatible with audio ?
In python I have
import serial
import time
import pyaudio
import threading
import signal
import sys
import wave
import datetime
import numpy as np
# Logging function with timestamps
def log(message):
print(f"[{datetime.datetime.now()}] {message}")
# Initialize the serial connection to the modem on COM9 with appropriate settings
def initialize_modem(port='COM9', baudrate=115200, timeout=1, write_timeout=20, rtscts=True, xonxoff=False):
try:
modem = serial.Serial(
port,
baudrate=baudrate,
timeout=timeout,
write_timeout=write_timeout,
rtscts=rtscts,
xonxoff=xonxoff
)
log("Serial connection to modem established.")
return modem
except serial.SerialException as e:
log(f"Failed to connect to modem: {e}")
sys.exit(1)
# Function to send AT command to modem and return full response
def send_at_command(modem, command, wait=2):
try:
log(f"Sending command: {command}")
modem.write((command + '\r').encode())
modem.flush() # Ensure command is sent
time.sleep(wait)
response = modem.read_all().decode(errors='ignore').strip()
log(f"Response: {response}")
return response
except serial.SerialTimeoutException:
log(f"Timeout occurred while sending command: {command}")
return ""
except Exception as e:
log(f"Unexpected error: {e}")
return ""
# Function to dial the phone number
def dial_phone_number(modem, phone_number):
response = send_at_command(modem, f'ATD{phone_number};')
if 'OK' in response or 'CONNECT' in response:
log(f"Dialing {phone_number}...")
time.sleep(5) # Wait for the call to establish
else:
log("Error dialing the number.")
# Function to check for call status (detect if call has dropped)
def check_call_status(modem):
response = send_at_command(modem, "AT+TRMSTATUS", wait=1) # Custom status command
if 'NO CARRIER' in response or 'BUSY' in response:
log("Call has ended or dropped.")
return False
return True
# Graceful shutdown handler for Ctrl+C
def shutdown_handler(signal, frame, modem, stop_event):
log("\nGracefully shutting down...")
stop_event.set()
send_at_command(modem, 'ATH') # Hang up the call
modem.close()
log("Modem connection closed.")
log("Shutdown complete.")
sys.exit(0)
# Function to continuously read incoming data from the modem (for control commands)
def read_from_modem(modem, stop_event):
while not stop_event.is_set():
try:
if modem.in_waiting > 0:
incoming = modem.read(modem.in_waiting).decode(errors='ignore')
if incoming:
log(f"Incoming: {incoming}")
except Exception as e:
log(f"Error reading from modem: {e}")
break
time.sleep(0.1) # Small delay to prevent CPU overuse
# Function to handle sending silence and receiving audio
def handle_audio(modem, silence_file, input_device_id, output_device_id, stop_event):
p = pyaudio.PyAudio()
# Open the silence audio file
try:
wf_silence = wave.open(silence_file, 'rb')
except FileNotFoundError:
log(f"Silence file '{silence_file}' not found.")
p.terminate()
return
except wave.Error as e:
log(f"Error opening silence file: {e}")
p.terminate()
return
# Ensure the silence file is correctly formatted
if wf_silence.getframerate() != 8000 or wf_silence.getsampwidth() != 2 or wf_silence.getnchannels() != 1:
log("Error: Silence file must be 8 kHz, 16-bit mono.")
wf_silence.close()
p.terminate()
return
# Audio settings
audio_format = pyaudio.paInt16
chunk_size = 160 # 10 ms of audio
# Open audio output stream (to send silence to modem)
try:
stream_out = p.open(
format=audio_format,
channels=wf_silence.getnchannels(),
rate=wf_silence.getframerate(),
output=True,
output_device_index=output_device_id,
frames_per_buffer=chunk_size
)
log(f"Audio output stream opened on device ID {output_device_id}.")
except Exception as e:
log(f"Failed to open audio output stream: {e}")
wf_silence.close()
p.terminate()
return
# Open a WAV file to save incoming audio
try:
wf_record = wave.open('incoming_audio.wav', 'wb')
wf_record.setnchannels(1)
wf_record.setsampwidth(p.get_sample_size(audio_format))
wf_record.setframerate(8000)
log("Incoming audio will be saved to 'incoming_audio.wav'.")
except Exception as e:
log(f"Failed to open 'incoming_audio.wav' for writing: {e}")
stream_out.close()
wf_silence.close()
p.terminate()
return
# Open audio input stream (to receive audio from modem)
try:
stream_in = p.open(
format=audio_format,
channels=1,
rate=8000,
input=True,
input_device_index=input_device_id,
frames_per_buffer=chunk_size
)
log(f"Audio input stream opened on device ID {input_device_id}.")
except Exception as e:
log(f"Failed to open audio input stream: {e}")
wf_record.close()
stream_out.close()
wf_silence.close()
p.terminate()
return
# Open audio playback stream (to play incoming audio)
try:
stream_play = p.open(
format=audio_format,
channels=1,
rate=8000,
output=True,
output_device_index=output_device_id,
frames_per_buffer=chunk_size
)
log(f"Audio playback stream opened on device ID {output_device_id}.")
except Exception as e:
log(f"Failed to open audio playback stream: {e}")
stream_in.close()
wf_record.close()
stream_out.close()
wf_silence.close()
p.terminate()
return
def audio_thread():
while not stop_event.is_set():
try:
# Send silence
silence_data = wf_silence.readframes(chunk_size // 2) # 80 frames * 2 bytes/frame = 160 bytes
if not silence_data:
wf_silence.rewind()
silence_data = wf_silence.readframes(chunk_size // 2)
if not silence_data:
log("Silence file is empty or corrupted.")
break
stream_out.write(silence_data)
# log("Sent silence to modem.")
# Receive audio from modem
incoming_data = stream_in.read(chunk_size, exception_on_overflow=False)
if incoming_data:
# Save incoming audio to WAV file
wf_record.writeframes(incoming_data)
log(f"Received {len(incoming_data)} bytes of audio data.")
# Log the first few bytes to verify content
log(f"First 10 bytes of incoming data: {incoming_data[:10]}")
# Play incoming audio through speakers
stream_play.write(incoming_data)
# Maintain real-time transmission
time.sleep(0.01) # 10 ms delay
except Exception as e:
log(f"Audio thread error: {e}")
stop_event.set()
# Start the audio thread
audio_thread_handle = threading.Thread(target=audio_thread, daemon=True)
audio_thread_handle.start()
log("Audio thread started: Sending silence, receiving and playing audio.")
# Wait for the stop_event to be set
while not stop_event.is_set():
time.sleep(0.1)
# Cleanup
stream_out.stop_stream()
stream_out.close()
stream_in.stop_stream()
stream_in.close()
stream_play.stop_stream()
stream_play.close()
wf_silence.close()
wf_record.close()
p.terminate()
log("Audio streams and WAV files closed. PyAudio terminated.")
# Main function
def main():
# Initialize modem
modem = initialize_modem()
# Event to signal threads to stop
stop_event = threading.Event()
# Set up signal handler for graceful shutdown
signal.signal(signal.SIGINT, lambda s, f: shutdown_handler(s, f, modem, stop_event))
# Step 1: Audio Mode already enabled manually
# Step 2: Skip setting microphone and speaker gains due to previous errors
# Step 3: Dial the phone number
dial_phone_number(modem, 'xxxxxxxxxx') # Replace with your target phone number
# Step 4: Start audio handling in a separate thread
# Ensure that you have correctly identified the input and output device IDs
input_device_id = 1 # Replace with your actual input device ID
output_device_id = 6 # Replace with your actual output device ID
silence_file = 'silence.wav' # Ensure this file exists and is correctly formatted
audio_thread = threading.Thread(
target=handle_audio,
args=(modem, silence_file, input_device_id, output_device_id, stop_event),
daemon=True
)
audio_thread.start()
log("Audio handling thread initiated.")
# Step 5: Start a thread to continuously read incoming data (control commands)
reader_thread = threading.Thread(target=read_from_modem, args=(modem, stop_event), daemon=True)
reader_thread.start()
log("Reader thread started.")
# Step 6: Monitor for call drop
try:
while True:
if not check_call_status(modem):
log("Call has been dropped.")
break
time.sleep(5) # Check every 5 seconds
except KeyboardInterrupt:
log("\nCall interrupted by user.")
finally:
# Signal all threads to stop
stop_event.set()
log("Signaled all threads to stop.")
# Wait for threads to finish
reader_thread.join(timeout=1)
log("Reader thread terminated.")
audio_thread.join(timeout=1)
log("Audio handling thread terminated.")
# Hang up the call
send_at_command(modem, 'ATH')
log("Call hung up.")
# Close the modem connection
modem.close()
log("Modem connection closed.")
log("Shutdown complete.")
if __name__ == "__main__":
main()
I can make and receive calls but no audio
I have tried various configs.
Any help appreciated.