C API usage. How to achieve some tasks

Hello everyone.

I am trying to learn asterisk C API. Great and very useful software, by the way.

I am hacking the codebase trying to figure out how to play a sequence of commands in asterisk from C/C++ (exclusively). This must be done in C/C++ since this is an exercise for training.

I am creating an application module that will call my application in the dialplan (in extensions.conf) as this:

[mycontext]
exten => _XX.,1,MyApp()

MyApp will execute all the logic for the call in the C/C++ module.

What I have for now is something like this (only shown relevant parts):


namespace {

int on_call_dialed(struct ast_channel * c,
const char * val) {
    if (ast_answer(c))
        ast_log(LOG_ERROR, "Error answering call\n");
    //Must filter dialed number
    //Must play sound.
    //Must write cdr
    //Must hangup
    return 0;
}

} //anonymous namespace

static ast_module_load_result load_module(void) {
    if (ast_register_application(
           aspire_dialplan_handler::k_app_name,
            &::on_call_dialed,
            "Test application",
            "Test application")) {
            ast_log(LOG_ERROR, "Could not load MyApp app module\n");
            return AST_MODULE_LOAD_FAILURE;
    }
    ast_log(LOG_NOTICE, "Loaded MyApp app module\n");

    return AST_MODULE_LOAD_SUCCESS;
}

My questions are:

1.- I need to filter the dialed phone number. How can I get the dialed number in on_call_dialed?
The function is being invoked when dialing, I tested.
2.- If 2 or more calls enter at nearly the same time in the same context, 2 instances of the same context will be created or the second call will be queued or refused, making my application slower under heavy load?
2.- I need to play a sound. I am aware of the Playback application. How could I use it from my C++ module without going to extensions.conf?
3.- Any idea of how to write to the cdr from C++ module?
3.- The callback invocation (I mean on_call_dialed) : is it fully asynchronous? What are the thread safety guarantees in general or any direction you could give me if it’s not asynchronous by default, so that I know how to protect relevant data structures to make everything more concurrent?

This is definitely the wrong forum. I’m not clear whether you want Asterisk Support or the developer mailing list, or another AMI gateway forum.

I can’t find on_call_dialled in the Asterisk source code, and searching for Asterisk “C API” result in references to a port of the asterisk-java AMI library to C++.

On the other hand, your dialplan fragment suggests you are creating an internal Asterisk application, as does the module load handling code.

I suppose it might be something new in Asterisk 12.

Assuming this is something new to Asterisk 12 and you are actually running in the Asterisk process, in which case this should be directed to the developer mailing list:

  1. c->exten

  2. Two channel instances will be created - contexts are static and there is no serialisation of access.

2a) The infrastructure for generating audio is quite complex. You should probably look at the beep generation in chan_agent.c. If you have a simple case, where the beep is being called when only the calling channel is up, you can probably invoke Playback. Examples of invoking application directly can be found in the code. I think there is a library routine that looks up the addres of an application.

  1. Asterisk API are C; you write to the cdr using the functions defined in cdr.h. Note CDRs are largely deprecated.

3a) As it doesn’t exist in any source code that I’ve looked at, I can’t answer for that. Please note that locking is complex in Asterisk and there is a mix of locking and reference counting approaches. Many Asterisk crashes are due to locking failures, particularly deadlocks. The specification for the callback should tell you whether or not c is locked, and whether or not c->tech_pvt is locked. (I would expect the callback to be synchronous, on the PBX thread for the call, but, as I said, it doesn’t exist up to Asterisk 11, so I don’t know for sure.)

If this is something new to Asterisk 12, I think you have taken on a project that is too difficult for your experience. If this is an AMI library, your choice of language is making things difficult, as the limited knowledge on this forum will probably apply mainly to PHP, with some Java; you will need to find a speciaist forum for the C++ library. If this is external, you almost certainly want AGI, not AMI.

It looks like you are calling the standard C application registration code. That will require an application without spaces. It will also require that the C++ environment converts a simple function reference to a method call.

Standard applications are run synchronously on the PBX thread. As far as I can tell, they are run with no locks held.

This is definitely a developer question, but I doubt that you will get much support from the developer list as there is no obvious benefit to the Asterisk community.

Also note that applications are not normally named after the event that would typically lead to the dialplan callling them; they are normally called _exec. Also, dialed would normally be understood to relate to the outgoing call and there is no facility to run dialplan at that stage. Furthermore, calling ast_answer is something that you should not do lightly, as it will start charging and frustrate failed call fallback logic at the calling end.

Hello again.

I am using asterisk 11.5.0 and I cannot find c->exten for the channel.

I greped all the source code and struct ast_channel is defined like this in channel.h:

#define AST_API_MODULE 1 /* gimme the inline defs! /
struct ast_channel
{
char x; /
basically empty! */
};

I don’t understand why. Are there any getters or setters to get the extension of the number? Is the internal structure associated in another way dinamically?

It would appear that version 11 makes the channel structure much more object like, with no public fields, than previous versions. However, it took me less than 10 minutes to answer your latest questions, even though, for the versions that I work with, my previous answer is correct.

Given, as I said, that this is not an appropriate forum, and I can’t see your getting much help on appropriate forums, for this sort of question, you are just going to have to read the code.

I cannot find an obvious place to post the question inside these forums.

Since my question was short and direct (the last one, I mean), I thought it wouldn’t be too inconvenient for you if I ask here.

Believe me, I’ve greped and looked for symbols with gnu global trying all of this:

ast_channel_*
ast_cel_fill_data_record (looked like close)

I looked at the pbx.h header.
I looked at channel.h full header.

And much more. Maybe you guessed right because you know the API style better than me.

And honestly, I cannot find an obvious way to do it.

Anyway, thanks for your support.

I see something like:

ast_channel_exten_set

But I cannot find the get equivalent. Anyway, I see what I want is the dialed number for the inbound call, but I have no clue of how to get it.

[quote=“germandiago”]I cannot find an obvious place to post the question inside these forums.
[/quote]

That’s because there is none. If you had got the forum even half right, and read the sticky postings, you would have found this one viewtopic.php?f=1&t=12322

There is not the developer expertise on these forums.

As a general principle, people won’t answer homework questions on the internet.

Developers have more important things to do that to teach the basics of how to understand the workings of very large pieces of third party software.

If you can’t find the getter, when it is so easy to find, my view is that you will get totally lost when you get to the real difficult bits, so it just isn’t worth my time to try and coach you.

From all accounts, you are using the wrong tool for the job - this should an AGI script in Perl or PHP. However, something you will learn in the real world is that one is often tasked to do things with the wrong tools, although usually one is expected to do things that should be done with low level tools, using high level ones, rather than your way round.