TRM240 EC21 can make and receive calls but no audio

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.

Hi @toolfolks
Requires an external codec to use audio.

Sorry I don’t understand.

What do I need to do to get it to work please.

How where please.

Any downloads links etc

See Hardware Design and Hardware Reference Design. EC21 requires external CodeC, and requires headphones, speaker, and mic