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.