Hi folk,
I am a newbie to asterisk. I am trying to hit azure speech to text rest api using RTC to get live results of audio received. I am working on a java application. I am stuck where the datagram socket receive the packets.
Asterisk is throwing me with a error
Can someone please help me with this?
[Oct 20 22:20:48] WARNING[16790]: res_http_websocket.c:559 ws_safe_read: Web socket closed abruptly
[Oct 20 22:20:48] WARNING[16790]: ari/ari_websockets.c:126 ast_ari_websocket_session_read: WebSocket read error: Success
Deactivating Stasis app ‘my_stasis_app’
== WebSocket connection from ‘127.0.0.1:43900’ closed
Activating Stasis app ‘my_stasis_app’
== WebSocket connection from ‘127.0.0.1:52702’ for protocol ‘’ accepted using version ‘13’
– Executing [1000@from-internal:1] NoOp(“PJSIP/1001-0000001e”, “Starting Stasis App”) in new stack
– Executing [1000@from-internal:2] Answer(“PJSIP/1001-0000001e”, “”) in new stack
> 0x7fc3380d8ea0 – Strict RTP learning after remote address set to: 172.26.160.1:60848
> 0x7fc3380d8ea0 – Strict RTP switching to RTP target address 172.26.160.1:60848 as source
– Executing [1000@from-internal:3] Stasis(“PJSIP/1001-0000001e”, “my_stasis_app”) in new stack
> 0x7fc3a8002320 – Strict RTP learning after remote address set to: 127.0.0.1:9999
– Called 127.0.0.1:9999/c(slin16)
– UnicastRTP/127.0.0.1:9999-0x7fc3a800e640 answered
> Launching Stasis(1729443054.105) on UnicastRTP/127.0.0.1:9999-0x7fc3a800e640
[Oct 20 22:20:55] ERROR[16836]: res_stasis.c:1349 stasis_app_exec: Stasis app ‘1729443054.105’ not registered
> 0x7fc3380d8ea0 – Strict RTP learning complete - Locking on source address 172.26.160.1:60848
The error means what it says. You created an external media channel and told it to go to ARI application “1729443054.105” which doesn’t exist/isn’t registered. It can’t do that, so it doesn’t. As to whether it should exist or not - only you know your application details.
Hi jcolp,
I have registered my app with the name “my_stasis_app” but i dont know why it is pinging the app with channel id.
my java code,
public class AriRtpListener {
private static final String ARI_URL = "http://localhost:8088";
private static final String USERNAME = "jagadish";
private static final String PASSWORD = "Jagadish@123";
private static final String AZURE_URL =
"https://centralindia.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=en-US&format=detailed";
private static final String AZURE_SPEECH_KEY = "";
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static final Logger logger = LoggerFactory.getLogger(AriRtpListener.class);
private ARI ari;
public static void main(String[] args) {
new AriRtpListener().start();
}
/**
* Initialize ARI connection and wait for incoming calls.
*/
public void start() {
try {
ari = ARI.build(ARI_URL, "my_stasis_app", USERNAME, PASSWORD, AriVersion.IM_FEELING_LUCKY);
ari.eventsCallback(new ch.loway.oss.ari4java.generated.AriWSHelper() {
@Override
protected void onStasisStart(StasisStart event) {
Channel channel = event.getChannel();
logger.info("Call received: Channel ID - {}", channel.getId());
executor.execute(() -> handleChannel(channel));
}
});
logger.info("Waiting for calls...");
Thread.sleep(Long.MAX_VALUE); // Keep main thread alive
} catch (Exception e) {
logger.error("Error initializing ARI", e);
}
}
/**
* Handle the incoming channel by connecting external media and streaming RTP.
*/
private void handleChannel(Channel channel) {
try {
// Connect external media to the channel
ari.channels().externalMedia(channel.getId(), "127.0.0.1:9999", "slin16").execute();
logger.info("External media connected to channel {}", channel.getId());
// Start receiving RTP packets and stream them to Azure
receiveRTPPackets(channel.getId());
} catch (ARIException e) {
logger.error("Error connecting external media: {}", e.getMessage(), e);
} catch (Exception e) {
logger.error("Unexpected error in handleChannel: {}", e.getMessage(), e);
}
}
/**
* Receive RTP packets and stream them to Azure.
*/
private void receiveRTPPackets(String channelId) {
logger.info("hit rtp");
try (DatagramSocket socket = new DatagramSocket(9999, InetAddress.getByName("127.0.0.1"))) {
logger.info("socket connected");
byte[] buffer = new byte[2048];
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
logger.info("Received packet data: {}", Arrays.toString(Arrays.copyOf(packet.getData(), packet.getLength())));
socket.receive(packet); // Receive RTP packet
logger.info("received packet");
// Strip off the RTP header (first 12 bytes)
byte[] audioData = new byte[packet.getLength() - 12];
System.arraycopy(packet.getData(), 12, audioData, 0, audioData.length);
// Stream audio data to Azure
streamAudioToAzure(audioData);
}
} catch (Exception e) {
logger.error("Error receiving RTP packets: {}", e.getMessage(), e);
}
}
/**
* Stream audio data to Azure Speech-to-Text API.
*/
private void streamAudioToAzure(byte[] audioData) {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost request = new HttpPost(URI.create(AZURE_URL));
// Set headers for Azure Speech-to-Text API
request.setHeader("Ocp-Apim-Subscription-Key", AZURE_SPEECH_KEY);
request.setHeader("Content-Type", "audio/wav; codecs=audio/pcm; samplerate=16000"); // Ensure this matches your audio format
request.setHeader("Accept", "application/json;text/plain"); // Accept JSON response
// Create the entity for the audio data
InputStreamEntity entity = new InputStreamEntity(new ByteArrayInputStream(audioData), audioData.length);
request.setEntity(entity);
// Send the request and process the response
String response = httpClient.execute(request, httpResponse -> {
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode != 200) {
String errorMessage = EntityUtils.toString(httpResponse.getEntity());
logger.error("Error response from Azure: Status Code - {}, Message - {}", statusCode, errorMessage);
return null; // Handle non-200 responses appropriately
}
return EntityUtils.toString(httpResponse.getEntity());
});
// Log the response from Azure
if (response != null) {
logger.info("Azure response: {}", response);
} else {
logger.error("Received an empty response from Azure.");
}
} catch (Exception e) {
logger.error("Error streaming to Azure: {}", e.getMessage(), e);
}
}
}
http.conf
[general]
servername=Asterisk
enabled=yes
bindaddr=0.0.0.0
bindport=8088
tlsenable=no
[ws]
enabled = yes
bindaddr = 0.0.0.0
bindport = 8088
[ari]
enabled=yes
ari.conf
[general]
enabled = yes
pretty = yes
[jagadish]
type = user
read_only = no
password = Jagadish@123
extensions.conf
[from-internal]
exten => 1001,1,Dial(PJSIP/1001)
exten => 1002,1,Dial(PJSIP/1002)
exten => 1000,1,NoOp(Starting Stasis App)
exten => 1000,n,Answer()
exten => 1000,n,Stasis(my_stasis_app)
exten => 1000,n,Hangup()
pjsip.conf
[transport-ws]
type = transport
protocol = ws
bind = 0.0.0.0:5060 ; Port for WebSocket connection
[transport-udp]
type=transport
protocol=udp ;udp,tcp,tls,ws,wss,flow
bind=0.0.0.0
[1001]
type=endpoint
transport=transport-udp
context=from-internal
disallow=all
allow=ulaw
auth=auth1001
aors=1001
[auth1001]
type=auth
auth_type=userpass
password=yourpassword
username=1001
[1001]
type=aor
max_contacts=1
[1002]
type=endpoint
transport=transport-udp
context=from-internal
disallow=all
allow=ulaw
auth=auth1002
aors=1002
[auth1002]
type=auth
auth_type=userpass
password=yourpassword2
username=1002
[1002]
type=aor
max_contacts=1
Please help me where i have gone wrong
Your problem is purely on your application side, so I would suggest looking at the arguments to the API calls in it. For example:
The first argument may be the ARI application to send the external media channel to.
Thank you so much jcolp, i tried it is throwing me with some other error will try to resolve it. Just confirm me whether am I going in the right direction for getting live stream data, or am i missing any asterisk feature?
External media is the method in ARI to send/receive media externally, and the method we recommend.
Thank you so much sir, wonderful community with wonderful people ![]()
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.