Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
jami-daemon
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Releases
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
savoirfairelinux
jami-daemon
Commits
a1f6c4ac
Commit
a1f6c4ac
authored
17 years ago
by
Alexandre Bourget
Browse files
Options
Downloads
Patches
Plain Diff
IAX: Dynamic codecs + Fixed samplerate conversion + Ability to receive calls
Added documentation.
parent
77751a2f
No related branches found
No related tags found
No related merge requests found
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
src/iaxcall.cpp
+83
-3
83 additions, 3 deletions
src/iaxcall.cpp
src/iaxcall.h
+42
-4
42 additions, 4 deletions
src/iaxcall.h
src/iaxvoiplink.cpp
+349
-203
349 additions, 203 deletions
src/iaxvoiplink.cpp
src/iaxvoiplink.h
+41
-3
41 additions, 3 deletions
src/iaxvoiplink.h
with
515 additions
and
213 deletions
src/iaxcall.cpp
+
83
−
3
View file @
a1f6c4ac
...
...
@@ -20,13 +20,93 @@
#include
"iaxcall.h"
#include
"global.h"
// for _debug
IAXCall
::
IAXCall
(
const
CallID
&
id
,
Call
::
CallType
type
)
:
Call
(
id
,
type
),
_session
(
0
)
IAXCall
::
IAXCall
(
const
CallID
&
id
,
Call
::
CallType
type
)
:
Call
(
id
,
type
),
_session
(
NULL
)
{
}
IAXCall
::~
IAXCall
()
{
_session
=
0
;
// just to be sure to don't have unknown pointer, do not delete it!
_session
=
NULL
;
// just to be sure to don't have unknown pointer, do not delete it!
}
void
IAXCall
::
setFormat
(
int
format
)
{
_format
=
format
;
switch
(
format
)
{
case
AST_FORMAT_ULAW
:
setAudioCodec
(
_codecMap
.
getCodec
(
PAYLOAD_CODEC_ULAW
));
break
;
case
AST_FORMAT_GSM
:
setAudioCodec
(
_codecMap
.
getCodec
(
PAYLOAD_CODEC_GSM
));
break
;
case
AST_FORMAT_ALAW
:
setAudioCodec
(
_codecMap
.
getCodec
(
PAYLOAD_CODEC_ALAW
));
break
;
case
AST_FORMAT_ILBC
:
setAudioCodec
(
_codecMap
.
getCodec
(
PAYLOAD_CODEC_ILBC
));
break
;
case
AST_FORMAT_SPEEX
:
setAudioCodec
(
_codecMap
.
getCodec
(
PAYLOAD_CODEC_SPEEX
));
break
;
default:
setAudioCodec
(
NULL
);
break
;
}
}
int
IAXCall
::
getSupportedFormat
()
{
CodecMap
map
=
getCodecMap
().
getMap
();
int
format
=
0
;
CodecMap
::
iterator
iter
=
map
.
begin
();
while
(
iter
!=
map
.
end
())
{
switch
(
iter
->
first
)
{
case
PAYLOAD_CODEC_ULAW
:
format
|=
AST_FORMAT_ULAW
;
break
;
case
PAYLOAD_CODEC_GSM
:
format
|=
AST_FORMAT_GSM
;
break
;
case
PAYLOAD_CODEC_ALAW
:
format
|=
AST_FORMAT_ALAW
;
break
;
case
PAYLOAD_CODEC_ILBC
:
format
|=
AST_FORMAT_ILBC
;
break
;
case
PAYLOAD_CODEC_SPEEX
:
format
|=
AST_FORMAT_SPEEX
;
break
;
default:
break
;
}
iter
++
;
}
return
format
;
}
int
IAXCall
::
getFirstMatchingFormat
(
int
needles
)
{
CodecMap
map
=
getCodecMap
().
getMap
();
int
format
=
0
;
CodecMap
::
iterator
iter
=
map
.
begin
();
while
(
iter
!=
map
.
end
())
{
switch
(
iter
->
first
)
{
case
PAYLOAD_CODEC_ULAW
:
format
=
AST_FORMAT_ULAW
;
break
;
case
PAYLOAD_CODEC_GSM
:
format
=
AST_FORMAT_GSM
;
break
;
case
PAYLOAD_CODEC_ALAW
:
format
=
AST_FORMAT_ALAW
;
break
;
case
PAYLOAD_CODEC_ILBC
:
format
=
AST_FORMAT_ILBC
;
break
;
case
PAYLOAD_CODEC_SPEEX
:
format
=
AST_FORMAT_SPEEX
;
break
;
default:
break
;
}
// Return the first that matches
if
(
format
&
needles
)
return
format
;
iter
++
;
}
return
0
;
}
This diff is collapsed.
Click to expand it.
src/iaxcall.h
+
42
−
4
View file @
a1f6c4ac
...
...
@@ -21,6 +21,7 @@
#include
"call.h"
#include
<iax/iax-client.h>
#include
<iax/frame.h>
/**
* IAXCall are IAX implementation of a normal Call
...
...
@@ -33,7 +34,7 @@ public:
~
IAXCall
();
/** Get the session pointer or
0
*/
/** Get the session pointer or
NULL
*/
struct
iax_session
*
getSession
()
{
return
_session
;
}
/** Set the session pointer
...
...
@@ -41,12 +42,49 @@ public:
*/
void
setSession
(
struct
iax_session
*
session
)
{
_session
=
session
;
}
void
setFormat
(
int
format
)
{
_format
=
format
;
}
/**
* Set format (one single bit
*
* This function sets the _audioCodec variable with the correct
* codec.
*/
void
setFormat
(
int
format
);
/**
* Get format
*/
int
getFormat
()
{
return
_format
;
}
/**
* Get the bitwise list of supported formats
*/
int
getSupportedFormat
();
/**
* Return a format (int) with the first matching codec selected.
*
* This considers the order of the appearance in the CodecMap,
* thus, the order of preference.
*
* NOTE: Everything returned is bound to the content of the local
* CodecMap, so it won't return format values that aren't valid
* in this call context.
*
* @param needles The format(s) (bitwise) you are looking for to match
* @return The matching format, thus 0 if none matches
*/
int
getFirstMatchingFormat
(
int
needles
);
private
:
/
/ e
ach call is associate
to a
session
/
** E
ach call is associate
d with an iax_
session
*/
struct
iax_session
*
_session
;
/**
* Format currently in use in the conversation,
* sent in each outgoing voice packet.
*/
int
_format
;
};
...
...
This diff is collapsed.
Click to expand it.
src/iaxvoiplink.cpp
+
349
−
203
View file @
a1f6c4ac
...
...
@@ -27,6 +27,7 @@
#include
<samplerate.h>
#include
<iax/iax-client.h>
#include
<math.h>
#define IAX_BLOCKING 1
...
...
@@ -39,33 +40,14 @@
// from IAXC : iaxclient.h
/* payload formats : WARNING: must match libiax values!!! */
/* Data formats for capabilities and frames alike */
#define IAX__FORMAT_G723_1 (1 << 0)
/* G.723.1 compression */
#define IAX__FORMAT_GSM (1 << 1)
/* GSM compression */
#define IAX__FORMAT_ULAW (1 << 2)
/* Raw mu-law data (G.711) */
#define IAX__FORMAT_ALAW (1 << 3)
/* Raw A-law data (G.711) */
#define IAX__FORMAT_G726 (1 << 4)
/* ADPCM, 32kbps */
#define IAX__FORMAT_ADPCM (1 << 5)
/* ADPCM IMA */
#define IAX__FORMAT_SLINEAR (1 << 6)
/* Raw 16-bit Signed Linear (8000 Hz) PCM */
#define IAX__FORMAT_LPC10 (1 << 7)
/* LPC10, 180 samples/frame */
#define IAX__FORMAT_G729A (1 << 8)
/* G.729a Audio */
#define IAX__FORMAT_SPEEX (1 << 9)
/* Speex Audio */
#define IAX__FORMAT_ILBC (1 << 10)
/* iLBC Audio */
#define IAX__FORMAT_MAX_AUDIO (1 << 15)
/* Maximum audio format */
#define IAX__FORMAT_JPEG (1 << 16)
/* JPEG Images */
#define IAX__FORMAT_PNG (1 << 17)
/* PNG Images */
#define IAX__FORMAT_H261 (1 << 18)
/* H.261 Video */
#define IAX__FORMAT_H263 (1 << 19)
/* H.263 Video */
#define IAX__FORMAT_H263_PLUS (1 << 20)
/* H.263+ Video */
#define IAX__FORMAT_MPEG4 (1 << 21)
/* MPEG4 Video */
#define IAX__FORMAT_H264 (1 << 23)
/* H264 Video */
#define IAX__FORMAT_THEORA (1 << 24)
/* Theora Video */
#define IAX__20S_8KHZ_MAX 320 // 320 samples
#define IAX__20S_48KHZ_MAX 1920 // 320*6 samples, 6 = 48000/8000
#define CHK_VALID_CALL if (call == NULL) { _debug("IAX: Call doesn't exists\n"); \
return false; }
IAXVoIPLink
::
IAXVoIPLink
(
const
AccountID
&
accountID
)
:
VoIPLink
(
accountID
)
{
...
...
@@ -75,7 +57,6 @@ IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
// to get random number for RANDOM_PORT
srand
(
time
(
NULL
));
audiocodec
=
NULL
;
audiolayer
=
NULL
;
_receiveDataDecoded
=
new
int16
[
IAX__20S_48KHZ_MAX
];
...
...
@@ -86,6 +67,11 @@ IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
_floatBuffer8000
=
new
float32
[
IAX__20S_8KHZ_MAX
];
_floatBuffer48000
=
new
float32
[
IAX__20S_48KHZ_MAX
];
_intBuffer8000
=
new
int16
[
IAX__20S_8KHZ_MAX
];
// libsamplerate-related
_src_state_mic
=
src_new
(
SRC_SINC_BEST_QUALITY
,
1
,
&
_src_err
);
_src_state_spkr
=
src_new
(
SRC_SINC_BEST_QUALITY
,
1
,
&
_src_err
);
}
...
...
@@ -95,7 +81,6 @@ IAXVoIPLink::~IAXVoIPLink()
_regSession
=
NULL
;
// shall not delete it
terminate
();
audiocodec
=
NULL
;
audiolayer
=
NULL
;
delete
[]
_intBuffer8000
;
_intBuffer8000
=
NULL
;
delete
[]
_floatBuffer48000
;
_floatBuffer48000
=
NULL
;
...
...
@@ -104,6 +89,10 @@ IAXVoIPLink::~IAXVoIPLink()
delete
[]
_sendDataEncoded
;
_sendDataEncoded
=
NULL
;
delete
[]
_receiveDataDecoded
;
_receiveDataDecoded
=
NULL
;
// libsamplerate-related
_src_state_mic
=
src_delete
(
_src_state_mic
);
_src_state_spkr
=
src_delete
(
_src_state_spkr
);
}
bool
...
...
@@ -133,8 +122,6 @@ IAXVoIPLink::init()
_evThread
->
start
();
// audio stuff, not dynamic yet
audiocodec
=
Manager
::
instance
().
getCodecDescriptorMap
().
getCodec
((
CodecType
)
0
);
audiolayer
=
Manager
::
instance
().
getAudioDriver
();
break
;
}
...
...
@@ -167,8 +154,8 @@ IAXVoIPLink::terminateIAXCall()
_mutexIAX
.
enterMutex
();
iax_hangup
(
call
->
getSession
(),
"Dumped Call"
);
_mutexIAX
.
leaveMutex
();
call
->
setSession
(
0
);
delete
call
;
call
=
0
;
call
->
setSession
(
NULL
);
delete
call
;
call
=
NULL
;
}
iter
++
;
}
...
...
@@ -183,45 +170,45 @@ IAXVoIPLink::getEvent()
iax_event
*
event
=
NULL
;
IAXCall
*
call
=
NULL
;
while
(
(
event
=
iax_get_event
(
IAX_BLOCKING
))
!=
NULL
)
{
//_debug ("Receive IAX Event: %d\n", event->etype);
while
(
(
event
=
iax_get_event
(
IAX_NONBLOCKING
))
!=
NULL
)
{
// If we received an 'ACK', libiax2 tells apps to ignore them.
if
(
event
->
etype
==
IAX_EVENT_NULL
)
{
continue
;
}
_debug
(
"Receive IAX Event: %d (0x%x)
\n
"
,
event
->
etype
,
event
->
etype
);
call
=
iaxFindCallBySession
(
event
->
session
);
if
(
call
!=
0
)
{
if
(
call
)
{
_debug
(
" - We've got an associated call, handle call event
\n
"
);
iaxHandleCallEvent
(
event
,
call
);
}
else
if
(
event
->
session
!=
0
&&
event
->
session
==
_regSession
)
{
}
else
if
(
event
->
session
&&
event
->
session
==
_regSession
)
{
_debug
(
" - We've got an associated REGISTRATION session, handle registration process
\n
"
);
// in iaxclient, there is many session handling, here, only one
iaxHandleRegReply
(
event
);
}
else
{
switch
(
event
->
etype
)
{
case
IAX_EVENT_REGACK
:
case
IAX_EVENT_REGREJ
:
_debug
(
"Unknown IAX Registration Event
\n
"
);
break
;
case
IAX_EVENT_REGREQ
:
_debug
(
"Registration by a peer, don't allow it
\n
"
);
break
;
case
IAX_EVENT_CONNECT
:
// new call
// New incoming call!
break
;
case
IAX_EVENT_TIMEOUT
:
// timeout for an unknown session
}
else
{
break
;
_debug
(
" - We've got some other event, deal with them alone.
\n
"
);
iaxHandlePrecallEvent
(
event
);
default:
_debug
(
"Unknown event type: %d
\n
"
,
event
->
etype
);
}
}
iax_event_free
(
event
);
}
// Woah, we should do that in another thread, which will always send out stuff..
// send sound here
if
(
_currentCall
!=
0
&&
audiolayer
!=
0
)
{
if
(
_currentCall
&&
audiolayer
)
{
int
samples
=
audiolayer
->
canGetMic
();
if
(
samples
!=
0
)
{
int
datalen
=
audiolayer
->
getMic
(
_sendDataEncoded
,
samples
);
_debug
(
"iax_send_voice(%p, %d, ,%d, %d)
\n
"
,
_currentCall
->
getSession
(),
_currentCall
->
getFormat
(),
datalen
,
samples
);
//
int datalen = audiolayer->getMic(_sendDataEncoded, samples);
//
_debug("iax_send_voice(%p, %d, ,%d, %d)\n", _currentCall->getSession(), _currentCall->getFormat(), datalen, samples);
//if ( iax_send_voice(_currentCall->getSession(), _currentCall->getFormat(), (char*)_sendDataEncoded, datalen, samples) == -1) {
// // error sending voice
//}
...
...
@@ -236,6 +223,22 @@ IAXVoIPLink::getEvent()
_evThread
->
sleep
(
5
);
}
IAXCall
*
IAXVoIPLink
::
getIAXCall
(
const
CallID
&
id
)
{
Call
*
call
=
getCall
(
id
);
if
(
call
)
{
return
dynamic_cast
<
IAXCall
*>
(
call
);
}
return
0
;
}
bool
IAXVoIPLink
::
setRegister
()
{
...
...
@@ -278,10 +281,13 @@ IAXVoIPLink::setRegister()
return
result
;
}
bool
IAXVoIPLink
::
setUnregister
()
{
if
(
_regSession
==
NULL
)
{
if
(
_regSession
)
{
// lock here
_mutexIAX
.
enterMutex
();
iax_destroy
(
_regSession
);
...
...
@@ -297,31 +303,36 @@ Call*
IAXVoIPLink
::
newOutgoingCall
(
const
CallID
&
id
,
const
std
::
string
&
toUrl
)
{
IAXCall
*
call
=
new
IAXCall
(
id
,
Call
::
Outgoing
);
if
(
call
)
{
call
->
setPeerNumber
(
toUrl
);
// we have to add the codec before using it in SIPOutgoingInvite...
//call->setCodecMap(Manager::instance().getCodecDescriptorMap());
if
(
iaxOutgoingInvite
(
call
)
)
{
call
->
setConnectionState
(
Call
::
Progressing
);
call
->
setState
(
Call
::
Active
);
addCall
(
call
);
}
else
{
delete
call
;
call
=
0
;
delete
call
;
call
=
NULL
;
}
}
return
call
;
}
bool
IAXVoIPLink
::
answer
(
const
CallID
&
id
)
{
IAXCall
*
call
=
getIAXCall
(
id
);
if
(
call
==
0
)
{
_debug
(
"Call doesn't exists
\n
"
);
return
false
;
}
CHK_VALID_CALL
;
_mutexIAX
.
enterMutex
();
iax_answer
(
call
->
getSession
());
_mutexIAX
.
leaveMutex
();
call
->
setState
(
Call
::
Active
);
call
->
setConnectionState
(
Call
::
Connected
);
return
true
;
}
...
...
@@ -329,12 +340,13 @@ bool
IAXVoIPLink
::
hangup
(
const
CallID
&
id
)
{
IAXCall
*
call
=
getIAXCall
(
id
);
if
(
call
==
0
)
{
_debug
(
"Call doesn't exists
\n
"
);
return
false
;
}
CHK_VALID_CALL
;
_mutexIAX
.
enterMutex
();
iax_hangup
(
call
->
getSession
(),
"Dumped Call"
);
_mutexIAX
.
leaveMutex
();
call
->
setSession
(
0
);
call
->
setSession
(
NULL
);
if
(
Manager
::
instance
().
isCurrentCall
(
id
))
{
// stop audio
}
...
...
@@ -346,11 +358,15 @@ bool
IAXVoIPLink
::
onhold
(
const
CallID
&
id
)
{
IAXCall
*
call
=
getIAXCall
(
id
);
if
(
call
==
0
)
{
_debug
(
"Call doesn't exists
\n
"
);
return
false
;
}
CHK_VALID_CALL
;
//if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; }
_mutexIAX
.
enterMutex
();
iax_quelch
(
call
->
getSession
());
_mutexIAX
.
leaveMutex
();
call
->
setState
(
Call
::
Hold
);
return
true
;
}
...
...
@@ -359,7 +375,9 @@ bool
IAXVoIPLink
::
offhold
(
const
CallID
&
id
)
{
IAXCall
*
call
=
getIAXCall
(
id
);
if
(
call
==
0
)
{
_debug
(
"Call doesn't exists
\n
"
);
return
false
;
}
CHK_VALID_CALL
;
//if (call->getState() == Call::Active) { _debug("Call is already active\n"); return false; }
_mutexIAX
.
enterMutex
();
iax_unquelch
(
call
->
getSession
());
...
...
@@ -372,7 +390,8 @@ bool
IAXVoIPLink
::
transfer
(
const
CallID
&
id
,
const
std
::
string
&
to
)
{
IAXCall
*
call
=
getIAXCall
(
id
);
if
(
call
==
0
)
{
_debug
(
"Call doesn't exists
\n
"
);
return
false
;
}
CHK_VALID_CALL
;
char
callto
[
to
.
length
()
+
1
];
strcpy
(
callto
,
to
.
c_str
());
...
...
@@ -389,7 +408,9 @@ bool
IAXVoIPLink
::
refuse
(
const
CallID
&
id
)
{
IAXCall
*
call
=
getIAXCall
(
id
);
if
(
call
==
0
)
{
_debug
(
"Call doesn't exists
\n
"
);
return
false
;
}
CHK_VALID_CALL
;
_mutexIAX
.
enterMutex
();
iax_reject
(
call
->
getSession
(),
"Call rejected manually."
);
_mutexIAX
.
leaveMutex
();
...
...
@@ -400,23 +421,25 @@ bool
IAXVoIPLink
::
carryingDTMFdigits
(
const
CallID
&
id
,
char
code
)
{
IAXCall
*
call
=
getIAXCall
(
id
);
if
(
call
==
0
)
{
_debug
(
"Call doesn't exists
\n
"
);
return
false
;
}
CHK_VALID_CALL
;
_mutexIAX
.
enterMutex
();
iax_send_dtmf
(
call
->
getSession
(),
code
);
_mutexIAX
.
leaveMutex
();
}
bool
IAXVoIPLink
::
iaxOutgoingInvite
(
IAXCall
*
call
)
{
struct
iax_session
*
newsession
;
// lock here
_mutexIAX
.
enterMutex
();
ost
::
MutexLock
m
(
_mutexIAX
);
newsession
=
iax_session_new
();
if
(
!
newsession
)
{
_debug
(
"IAX Error: Can't make new session for a new call
\n
"
);
// unlock here
_mutexIAX
.
leaveMutex
();
return
false
;
}
call
->
setSession
(
newsession
);
...
...
@@ -433,14 +456,13 @@ IAXVoIPLink::iaxOutgoingInvite(IAXCall* call)
char
*
lang
=
NULL
;
int
wait
=
0
;
int
audio_format_preferred
=
IAX__FORMAT_ULAW
;
int
audio_format_capability
=
IAX__FORMAT_ULAW
;
// | IAX__FORMAT_ALAW | IAX__FORMAT_GSM | IAX__FORMAT_SPEEX;
/** @todo Make preference dynamic, and configurable */
int
audio_format_preferred
=
call
->
getFirstMatchingFormat
(
call
->
getSupportedFormat
());
int
audio_format_capability
=
call
->
getSupportedFormat
();
_debug
(
"IAX New call: %s
\n
"
,
num
);
iax_call
(
newsession
,
user
,
user
,
num
,
lang
,
wait
,
audio_format_preferred
,
audio_format_capability
);
// unlock here
_mutexIAX
.
leaveMutex
();
return
true
;
}
...
...
@@ -451,7 +473,7 @@ IAXVoIPLink::iaxFindCallBySession(struct iax_session* session)
// access to callMap shoud use that
// the code below is like findSIPCallWithCid()
ost
::
MutexLock
m
(
_callMapMutex
);
IAXCall
*
call
=
0
;
IAXCall
*
call
=
NULL
;
CallMap
::
iterator
iter
=
_callMap
.
begin
();
while
(
iter
!=
_callMap
.
end
())
{
call
=
dynamic_cast
<
IAXCall
*>
(
iter
->
second
);
...
...
@@ -460,7 +482,7 @@ IAXVoIPLink::iaxFindCallBySession(struct iax_session* session)
}
iter
++
;
}
return
0
;
// not found
return
NULL
;
// not found
}
void
...
...
@@ -496,7 +518,11 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
case
IAX_EVENT_ACCEPT
:
// accept
//
if
(
event
->
ies
.
format
)
{
call
->
setFormat
(
event
->
ies
.
format
);
}
break
;
case
IAX_EVENT_ANSWER
:
...
...
@@ -504,7 +530,10 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
call
->
setConnectionState
(
Call
::
Connected
);
call
->
setState
(
Call
::
Active
);
if
(
event
->
ies
.
format
)
{
// Should not get here, should have been set in EVENT_ACCEPT
call
->
setFormat
(
event
->
ies
.
format
);
}
Manager
::
instance
().
peerAnsweredCall
(
id
);
_currentCall
=
call
;
...
...
@@ -525,18 +554,42 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
break
;
case
IAX_EVENT_VOICE
:
if
(
audiocodec
!=
NULL
&&
audiolayer
!=
NULL
)
{
//_debug("Receive: len=%d, format=%d, _receiveDataDecoded=%p\n", event->datalen, call->getFormat(), _receiveDataDecoded);
if
(
audiolayer
)
{
AudioCodec
*
audiocodec
=
call
->
getAudioCodec
();
if
(
!
audiocodec
)
{
// libiax2 stores the voiceformat in the 'subclass' element.
if
(
event
->
subclass
)
{
// Set the format, with the first voice packet
call
->
setFormat
(
event
->
subclass
);
audiocodec
=
call
->
getAudioCodec
();
}
else
{
// Send a VNAK, because they sent a Mini packet before
// a full VOICE packet (with the format inside)
_debug
(
"IAX: sending VNAK, received mini packet before full VOICE packet."
);
iax_vnak
(
event
->
session
);
break
;
}
}
_debug
(
"Receive: len=%d, format=%d, _receiveDataDecoded=%p
\n
"
,
event
->
datalen
,
call
->
getFormat
(),
_receiveDataDecoded
);
unsigned
char
*
data
=
(
unsigned
char
*
)
event
->
data
;
unsigned
int
size
=
event
->
datalen
;
if
(
size
>
IAX__20S_8KHZ_MAX
)
{
_debug
(
"
t
he size %d is bigger than expected %d.
crop
\n
"
,
size
,
IAX__20S_8KHZ_MAX
);
_debug
(
"
T
he size %d is bigger than expected %d.
Packet cropped. Ouch!
\n
"
,
size
,
IAX__20S_8KHZ_MAX
);
size
=
IAX__20S_8KHZ_MAX
;
}
// On pourrait ajuster le codec dynamiquement ici, comme c'est fait dans SIP.
// à moins que IAX ne permette pas de changer le codec à chaque paquet.
int
expandedSize
=
audiocodec
->
codecDecode
(
_receiveDataDecoded
,
data
,
size
);
int
nbInt16
=
expandedSize
/
sizeof
(
int16
);
if
(
nbInt16
>
IAX__20S_8KHZ_MAX
)
{
_debug
(
"We have decoded a IAX packet larger than expected: %s VS %s.
c
rop
\n
"
,
nbInt16
,
IAX__20S_8KHZ_MAX
);
_debug
(
"We have decoded a IAX
VOICE
packet larger than expected: %s VS %s.
C
rop
ping.
\n
"
,
nbInt16
,
IAX__20S_8KHZ_MAX
);
nbInt16
=
IAX__20S_8KHZ_MAX
;
}
...
...
@@ -544,18 +597,21 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
int
nbSample
=
nbInt16
;
int
nbSampleMaxRate
=
nbInt16
*
6
;
if
(
audiolayer
->
getSampleRate
()
!=
audiocodec
->
getClockRate
()
)
{
// convert here
if
(
audiolayer
->
getSampleRate
()
!=
audiocodec
->
getClockRate
()
&&
nbSample
)
{
// Do sample rate conversion
double
factord
=
(
double
)
audiolayer
->
getSampleRate
()
/
audiocodec
->
getClockRate
();
// SRC_DATA from samplerate.h
SRC_DATA
src_data
;
src_data
.
data_in
=
_floatBuffer8000
;
src_data
.
data_out
=
_floatBuffer48000
;
src_data
.
input_frames
=
nbSample
;
src_data
.
output_frames
=
nbSample
MaxRate
;
src_data
.
output_frames
=
(
int
)
floor
(
factord
*
nbSample
)
;
src_data
.
src_ratio
=
factord
;
src_data
.
end_of_input
=
0
;
/* More data will come */
src_short_to_float_array
(
_receiveDataDecoded
,
_floatBuffer8000
,
nbSample
);
src_simple
(
&
src_data
,
SRC_SINC_BEST_QUALITY
/*SRC_SINC_MEDIUM_QUALITY*/
,
1
);
// 1=mono channel
// samplerate convert, go!
src_process
(
_src_state_spkr
,
&
src_data
);
nbSample
=
(
src_data
.
output_frames_gen
>
IAX__20S_48KHZ_MAX
)
?
IAX__20S_48KHZ_MAX
:
src_data
.
output_frames_gen
;
#ifdef DATAFORMAT_IS_FLOAT
...
...
@@ -576,6 +632,8 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
#endif
}
audiolayer
->
putMain
(
toAudioLayer
,
nbSample
*
sizeof
(
SFLDataFormat
));
}
else
{
_debug
(
"IAX: incoming audio, but no sound card open"
);
}
break
;
...
...
@@ -607,26 +665,114 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
}
/**
* Handle the registration process
*/
void
IAXVoIPLink
::
iaxHandleRegReply
(
iax_event
*
event
)
{
//unregister
if
(
event
->
etype
==
IAX_EVENT_REGREJ
)
{
/* Authentication failed! */
iax_destroy
(
_regSession
);
_regSession
=
NULL
;
Manager
::
instance
().
registrationFailed
(
getAccountID
());
}
else
if
(
event
->
etype
==
IAX_EVENT_REGACK
)
{
}
else
if
(
event
->
etype
==
IAX_EVENT_REGACK
)
{
/* Authentication succeeded */
Manager
::
instance
().
registrationSucceed
(
getAccountID
());
}
}
IAXCall
*
IAXVoIPLink
::
getIAXCall
(
const
CallID
&
id
)
void
IAXVoIPLink
::
iaxHandlePrecallEvent
(
iax_event
*
event
)
{
Call
*
call
=
getCall
(
id
);
if
(
call
)
{
return
dynamic_cast
<
IAXCall
*>
(
call
);
IAXCall
*
call
=
NULL
;
CallID
id
;
switch
(
event
->
etype
)
{
case
IAX_EVENT_REGACK
:
case
IAX_EVENT_REGREJ
:
_debug
(
"IAX Registration Event in a pre-call setup
\n
"
);
break
;
case
IAX_EVENT_REGREQ
:
// Received when someone wants to register to us!?!
// Asterisk receives and answers to that, not us, we're a phone.
_debug
(
"Registration by a peer, don't allow it
\n
"
);
break
;
case
IAX_EVENT_CONNECT
:
// We've got an incoming call! Yikes!
_debug
(
"> IAX_EVENT_CONNECT (receive)
\n
"
);
id
=
Manager
::
instance
().
getNewCallID
();
call
=
new
IAXCall
(
id
,
Call
::
Incoming
);
if
(
!
call
)
{
_debug
(
"! IAX Failure: unable to create an incoming call"
);
return
;
}
return
0
;
// Setup the new IAXCall
// Associate the call to the session.
call
->
setSession
(
event
->
session
);
// setCallAudioLocal(call);
call
->
setCodecMap
(
Manager
::
instance
().
getCodecDescriptorMap
());
call
->
setConnectionState
(
Call
::
Progressing
);
if
(
event
->
ies
.
calling_number
)
call
->
setPeerNumber
(
std
::
string
(
event
->
ies
.
calling_number
));
if
(
event
->
ies
.
calling_name
)
call
->
setPeerName
(
std
::
string
(
event
->
ies
.
calling_name
));
if
(
Manager
::
instance
().
incomingCall
(
call
,
getAccountID
()))
{
/** @todo Faudra considérer éventuellement le champ CODEC PREFS pour
* l'établissement du codec de transmission */
// Remote lists its capabilities
int
format
=
call
->
getFirstMatchingFormat
(
event
->
ies
.
capability
);
// Remote asks for preferred codec voiceformat
int
pref_format
=
call
->
getFirstMatchingFormat
(
event
->
ies
.
format
);
// Priority to remote's suggestion. In case it's a forwarding, no transcoding
// will be needed from the server, thus less latency.
if
(
pref_format
)
format
=
pref_format
;
iax_accept
(
event
->
session
,
format
);
iax_ring_announce
(
event
->
session
);
addCall
(
call
);
}
else
{
// reject call, unable to add it
iax_reject
(
event
->
session
,
"Error ringing user."
);
delete
call
;
call
=
NULL
;
}
break
;
case
IAX_EVENT_HANGUP
:
// Remote peer hung up
call
=
iaxFindCallBySession
(
event
->
session
);
id
=
call
->
getCallId
();
Manager
::
instance
().
peerHungupCall
(
id
);
removeCall
(
id
);
break
;
case
IAX_EVENT_TIMEOUT
:
// timeout for an unknown session
break
;
default
:
_debug
(
"Unknown event type: %d
\n
"
,
event
->
etype
);
}
}
This diff is collapsed.
Click to expand it.
src/iaxvoiplink.h
+
41
−
3
View file @
a1f6c4ac
...
...
@@ -22,6 +22,7 @@
#include
"voiplink.h"
#include
<iax/iax-client.h>
#include
"global.h"
#include
<samplerate.h>
class
EventThread
;
...
...
@@ -49,6 +50,15 @@ public:
void
terminate
(
void
);
bool
setRegister
(
void
);
/**
* Destroy registration session
*
* @todo Send an IAX_COMMAND_REGREL to force unregistration upstream.
* Urgency: low
*
* @return bool If we're registered upstream
*/
bool
setUnregister
(
void
);
Call
*
newOutgoingCall
(
const
CallID
&
id
,
const
std
::
string
&
toUrl
);
...
...
@@ -101,26 +111,45 @@ private:
*/
void
iaxHandleRegReply
(
iax_event
*
event
);
/**
* Handle IAX pre-call setup-related events
* @param event An iax_event pointer
*/
void
iaxHandlePrecallEvent
(
iax_event
*
event
);
/**
* Send an outgoing call invite to iax
* @param call An IAXCall pointer
*/
bool
iaxOutgoingInvite
(
IAXCall
*
Call
);
bool
iaxOutgoingInvite
(
IAXCall
*
call
);
/**
* Convert CodecMap to IAX format using IAX constants
* @return `format` ready to go into iax_* calls
*/
int
iaxCodecMapToFormat
(
IAXCall
*
call
);
/** Threading object */
EventThread
*
_evThread
;
/** registration session : 0 if not register */
struct
iax_session
*
_regSession
;
/** IAX Host */
std
::
string
_host
;
/** IAX User */
std
::
string
_user
;
/** IAX Password */
std
::
string
_pass
;
/** IAX full name */
std
::
string
_fullName
;
ost
::
Mutex
_mutexIAX
;
// extra pointer / not dynamic yet
AudioCodec
*
audiocodec
;
AudioLayer
*
audiolayer
;
/** When we receive data, we decode it inside this buffer */
...
...
@@ -140,6 +169,15 @@ private:
/** Buffer for 8000hz samples for mic conversion */
int16
*
_intBuffer8000
;
/** libsamplerate converter for incoming voice */
SRC_STATE
*
_src_state_spkr
;
/** libsamplerate converter for outgoing voice */
SRC_STATE
*
_src_state_mic
;
/** libsamplerate error */
int
_src_err
;
/** Current IAX call pointer, used for sending, change when starting audio, switching */
IAXCall
*
_currentCall
;
};
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment