mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-23 12:42:02 +00:00
Merge remote-tracking branch 'fsorig/master'
This commit is contained in:
@@ -193,6 +193,12 @@ struct switch_media_bug {
|
||||
switch_thread_id_t thread_id;
|
||||
char *function;
|
||||
char *target;
|
||||
switch_codec_implementation_t read_impl;
|
||||
switch_codec_implementation_t write_impl;
|
||||
switch_timer_t timer;
|
||||
uint32_t last_read_ts;
|
||||
uint32_t last_write_ts;
|
||||
switch_frame_t *ping_frame;
|
||||
struct switch_media_bug *next;
|
||||
};
|
||||
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
#include "switch_platform.h"
|
||||
#include "switch_types.h"
|
||||
#include "switch_apr.h"
|
||||
#include "switch_curl.h"
|
||||
#include "switch_mprintf.h"
|
||||
#include "switch_core_db.h"
|
||||
#include "switch_dso.h"
|
||||
|
||||
@@ -591,7 +591,10 @@ SWITCH_DECLARE(void) switch_channel_event_set_extended_data(_In_ switch_channel_
|
||||
\return the original string if no expansion takes place otherwise a new string that must be freed
|
||||
\note it's necessary to test if the return val is the same as the input and free the string if it is not.
|
||||
*/
|
||||
SWITCH_DECLARE(char *) switch_channel_expand_variables(_In_ switch_channel_t *channel, _In_ const char *in);
|
||||
SWITCH_DECLARE(char *) switch_channel_expand_variables_check(switch_channel_t *channel, const char *in, switch_event_t *var_list, switch_event_t *api_list);
|
||||
#define switch_channel_expand_variables(_channel, _in) switch_channel_expand_variables_check(_channel, _in, NULL, NULL)
|
||||
|
||||
|
||||
SWITCH_DECLARE(char *) switch_channel_build_param_string(_In_ switch_channel_t *channel, _In_opt_ switch_caller_profile_t *caller_profile,
|
||||
_In_opt_ const char *prefix);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(_In_ switch_channel_t *channel);
|
||||
|
||||
@@ -995,7 +995,9 @@ SWITCH_DECLARE(void) switch_core_thread_session_end(_In_ switch_core_session_t *
|
||||
\brief Launch a service thread on a session to drop inbound data
|
||||
\param session the session the launch thread on
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_core_service_session(_In_ switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_service_session_av(_In_ switch_core_session_t *session, switch_bool_t audio, switch_bool_t video);
|
||||
#define switch_core_service_session(_s) switch_core_service_session_av(_s, SWITCH_TRUE, SWITCH_FALSE)
|
||||
|
||||
|
||||
/*!
|
||||
\brief Request an outgoing session spawned from an existing session using a desired endpoing module
|
||||
@@ -1467,6 +1469,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_codec_destroy(switch_codec_t *codec)
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_codec(_In_ switch_core_session_t *session, switch_codec_t *codec);
|
||||
|
||||
/*!
|
||||
\brief Assign the original read codec to a given session. This is the read codec used by an endpoint.
|
||||
\param session session to add the codec to
|
||||
\param codec the codec to add
|
||||
\return SWITCH_STATUS_SUCCESS if successful
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_set_real_read_codec(_In_ switch_core_session_t *session, switch_codec_t *codec);
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_session_unset_read_codec(_In_ switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_session_unset_write_codec(_In_ switch_core_session_t *session);
|
||||
|
||||
@@ -2115,6 +2125,7 @@ SWITCH_DECLARE(uint32_t) switch_core_default_dtmf_duration(uint32_t duration);
|
||||
SWITCH_DECLARE(switch_status_t) switch_console_set_complete(const char *string);
|
||||
SWITCH_DECLARE(switch_status_t) switch_console_set_alias(const char *string);
|
||||
SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait);
|
||||
SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream);
|
||||
SWITCH_DECLARE(void) switch_cond_yield(switch_interval_time_t t);
|
||||
SWITCH_DECLARE(void) switch_cond_next(void);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_chat_send_args(const char *dest_proto, const char *proto, const char *from, const char *to,
|
||||
@@ -2302,7 +2313,8 @@ SWITCH_DECLARE(char *) switch_say_file_handle_detach_path(switch_say_file_handle
|
||||
SWITCH_DECLARE(void) switch_say_file_handle_destroy(switch_say_file_handle_t **sh);
|
||||
SWITCH_DECLARE(switch_status_t) switch_say_file_handle_create(switch_say_file_handle_t **sh, const char *ext, switch_event_t **var_event);
|
||||
SWITCH_DECLARE(void) switch_say_file(switch_say_file_handle_t *sh, const char *fmt, ...);
|
||||
|
||||
SWITCH_DECLARE(int) switch_max_file_desc(void);
|
||||
SWITCH_DECLARE(void) switch_close_extra_files(int *keep, int keep_ttl);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
@@ -49,7 +49,7 @@ SWITCH_DECLARE(switch_CURLcode) switch_curl_easy_setopt(CURL *handle, switch_CUR
|
||||
SWITCH_DECLARE(const char *) switch_curl_easy_strerror(switch_CURLcode errornum );
|
||||
SWITCH_DECLARE(void) switch_curl_init(void);
|
||||
SWITCH_DECLARE(void) switch_curl_destroy(void);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_curl_process_form_post_params(switch_event_t *event, switch_CURL *curl_handle, struct curl_httppost **formpostp);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -104,7 +104,8 @@ struct switch_event {
|
||||
|
||||
typedef enum {
|
||||
EF_UNIQ_HEADERS = (1 << 0),
|
||||
EF_NO_CHAT_EXEC = (1 << 1)
|
||||
EF_NO_CHAT_EXEC = (1 << 1),
|
||||
EF_DEFAULT_ALLOW = (1 << 2)
|
||||
} switch_event_flag_t;
|
||||
|
||||
|
||||
@@ -329,7 +330,8 @@ SWITCH_DECLARE(switch_status_t) switch_event_add_body(switch_event_t *event, con
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_set_body(switch_event_t *event, const char *body);
|
||||
|
||||
SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const char *in);
|
||||
SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list);
|
||||
#define switch_event_expand_headers(_event, _in) switch_event_expand_headers_check(_event, _in, NULL, NULL)
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_create_pres_in_detailed(_In_z_ char *file, _In_z_ char *func, _In_ int line,
|
||||
_In_z_ const char *proto, _In_z_ const char *login,
|
||||
@@ -399,7 +401,7 @@ SWITCH_DECLARE(void) switch_event_deliver(switch_event_t **event);
|
||||
#define switch_event_fire_data(event, data) switch_event_fire_detailed(__FILE__, (const char * )__SWITCH_FUNC__, __LINE__, event, data)
|
||||
|
||||
SWITCH_DECLARE(char *) switch_event_build_param_string(switch_event_t *event, const char *prefix, switch_hash_t *vars_map);
|
||||
|
||||
SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t *list, const char *name);
|
||||
///\}
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
||||
@@ -162,13 +162,18 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_count(switch_core_sess
|
||||
\param mod_name the module name of the ASR library
|
||||
\param grammar the grammar text, URI, or local file name
|
||||
\param result of speech recognition, allocated from the session pool
|
||||
\param input_timeout time to wait for input
|
||||
\param args arguements to pass for callbacks etc
|
||||
\return SWITCH_STATUS_SUCCESS if all is well
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_play_and_detect_speech(switch_core_session_t *session,
|
||||
const char *file,
|
||||
const char *mod_name,
|
||||
const char *grammar,
|
||||
char **result);
|
||||
const char *file,
|
||||
const char *mod_name,
|
||||
const char *grammar,
|
||||
char **result,
|
||||
uint32_t input_timeout,
|
||||
switch_input_args_t *args);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Engage background Speech detection on a session
|
||||
@@ -911,6 +916,7 @@ SWITCH_DECLARE(switch_bool_t) switch_ivr_uuid_exists(const char *uuid);
|
||||
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_last_ping(switch_ivr_dmachine_t *dmachine);
|
||||
SWITCH_DECLARE(const char *) switch_ivr_dmachine_get_name(switch_ivr_dmachine_t *dmachine);
|
||||
SWITCH_DECLARE(void) switch_ivr_dmachine_set_match_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t match_callback);
|
||||
SWITCH_DECLARE(void) switch_ivr_dmachine_set_nonmatch_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t nonmatch_callback);
|
||||
|
||||
+29
-29
@@ -61,56 +61,56 @@ typedef struct cJSON_Hooks {
|
||||
} cJSON_Hooks;
|
||||
|
||||
// Supply malloc, realloc and free functions to cJSON
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
SWITCH_DECLARE(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished.
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_Parse(const char *value);
|
||||
// Render a cJSON entity to text for transfer/storage. Free the char* when finished.
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
SWITCH_DECLARE(char *)cJSON_Print(cJSON *item);
|
||||
// Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished.
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
SWITCH_DECLARE(char *)cJSON_PrintUnformatted(cJSON *item);
|
||||
// Delete a cJSON entity and all subentities.
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
SWITCH_DECLARE(void) cJSON_Delete(cJSON *c);
|
||||
|
||||
// Returns the number of items in an array (or object).
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
SWITCH_DECLARE(int) cJSON_GetArraySize(cJSON *array);
|
||||
// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item);
|
||||
// Get item "string" from object. Case insensitive.
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
// These calls create a cJSON item of the appropriate type.
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateNull(void);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateTrue(void);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateFalse(void);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateNumber(double num);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateString(const char *string);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateArray(void);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateObject(void);
|
||||
|
||||
// These utilities create an Array of count items.
|
||||
extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(float *numbers,int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count);
|
||||
|
||||
// Append item to the specified array/object.
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
SWITCH_DECLARE(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
SWITCH_DECLARE(void) cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
// Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON.
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||
SWITCH_DECLARE(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
SWITCH_DECLARE(void) cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||
|
||||
// Remove/Detatch items from Arrays/Objects.
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||
SWITCH_DECLARE(void) cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||
SWITCH_DECLARE(cJSON *)cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||
SWITCH_DECLARE(void) cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||
|
||||
// Update array items.
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
SWITCH_DECLARE(void) cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
SWITCH_DECLARE(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
#define __SWITCH_SSL_H
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
#if defined (MACOSX) || defined(DARWIN)
|
||||
/* Disable depricated-declarations on OS X */
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
static switch_mutex_t **ssl_mutexes;
|
||||
|
||||
@@ -785,6 +785,12 @@ typedef struct {
|
||||
#pragma pack(pop, r1)
|
||||
#endif
|
||||
|
||||
typedef struct audio_buffer_header_s {
|
||||
uint32_t ts;
|
||||
uint32_t len;
|
||||
} audio_buffer_header_t;
|
||||
|
||||
|
||||
/*!
|
||||
\enum switch_priority_t
|
||||
\brief Priority Indication
|
||||
@@ -1199,6 +1205,9 @@ typedef enum {
|
||||
CF_ZOMBIE_EXEC,
|
||||
CF_INTERCEPT,
|
||||
CF_INTERCEPTED,
|
||||
CF_VIDEO_REFRESH_REQ,
|
||||
CF_SERVICE_AUDIO,
|
||||
CF_SERVICE_VIDEO,
|
||||
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
|
||||
/* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */
|
||||
CF_FLAG_MAX
|
||||
|
||||
@@ -834,6 +834,9 @@ SWITCH_DECLARE(const char *) switch_inet_ntop(int af, void const *src, char *dst
|
||||
SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len);
|
||||
SWITCH_DECLARE(char *) switch_format_number(const char *num);
|
||||
|
||||
SWITCH_DECLARE(unsigned int) switch_atoui(const char *nptr);
|
||||
SWITCH_DECLARE(unsigned long) switch_atoul(const char *nptr);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
BASE=../../../..
|
||||
include $(BASE)/build/modmake.rules
|
||||
@@ -0,0 +1,287 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mod_abstraction"
|
||||
ProjectGUID="{BDA173DB-F8EF-4270-9553-B453AF92E43A}"
|
||||
RootNamespace="mod_abstraction"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\mod_abstraction.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>mod_abstraction</ProjectName>
|
||||
<ProjectGuid>{60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}</ProjectGuid>
|
||||
<RootNamespace>mod_abstraction</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_abstraction.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* mod_abstraction.c -- Abstraction
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_abstraction_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_abstraction_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_abstraction_load);
|
||||
|
||||
const char *global_cf = "abstraction.conf";
|
||||
|
||||
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
|
||||
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
|
||||
*/
|
||||
SWITCH_MODULE_DEFINITION(mod_abstraction, mod_abstraction_load, mod_abstraction_shutdown, NULL);
|
||||
|
||||
SWITCH_STANDARD_API(api_abstraction_function)
|
||||
{
|
||||
const char *api_name = switch_event_get_header(stream->param_event, "API-Command");
|
||||
switch_xml_t cfg, xml, x_apis, x_api;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(x_apis = switch_xml_child(cfg, "apis"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No apis group\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((x_api = switch_xml_find_child_multi(x_apis, "api", "name", api_name , NULL))) {
|
||||
const char *parse = switch_xml_attr_soft(x_api, "parse");
|
||||
const char *destination = switch_xml_attr_soft(x_api, "destination");
|
||||
const char *arguments = switch_xml_attr_soft(x_api, "argument");
|
||||
|
||||
int proceed = 0;
|
||||
switch_regex_t *re = NULL;
|
||||
int ovector[30];
|
||||
|
||||
if ((proceed = switch_regex_perform(cmd, parse, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
const char *api_args = NULL;
|
||||
char *substituted = NULL;
|
||||
|
||||
if (cmd && strchr(parse, '(')) {
|
||||
uint32_t len = (uint32_t) (strlen(cmd) + strlen(arguments) + 10) * proceed;
|
||||
if (!(substituted = malloc(len))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||
proceed = 0;
|
||||
goto end;
|
||||
}
|
||||
memset(substituted, 0, len);
|
||||
switch_perform_substitution(re, proceed, arguments, cmd , substituted, len, ovector);
|
||||
api_args = substituted;
|
||||
} else {
|
||||
api_args = arguments;
|
||||
}
|
||||
switch_api_execute(destination, api_args, session, stream);
|
||||
|
||||
switch_safe_free(substituted);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No match for API %s (%s != %s)\n", api_name, parse, cmd);
|
||||
}
|
||||
switch_regex_safe_free(re);
|
||||
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "API %s doesn't exist inside the xml structure. You might have forgot to reload the module after editing it\n", api_name);
|
||||
}
|
||||
|
||||
end:
|
||||
if (xml)
|
||||
switch_xml_free(xml);
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Macro expands to: switch_status_t mod_abstraction_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_abstraction_load)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_TERM;
|
||||
switch_api_interface_t *api_interface;
|
||||
switch_xml_t cfg, xml, x_apis, x_api;
|
||||
int count = 0;
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(x_apis = switch_xml_child(cfg, "apis"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No apis group\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (x_api = switch_xml_child(x_apis, "api"); x_api; x_api = x_api->next) {
|
||||
const char *name = switch_xml_attr_soft(x_api, "name");
|
||||
const char *description = switch_xml_attr_soft(x_api, "description");
|
||||
const char *syntax = switch_xml_attr_soft(x_api, "syntax");
|
||||
SWITCH_ADD_API(api_interface, name, description, api_abstraction_function, syntax);
|
||||
count++;
|
||||
|
||||
}
|
||||
if (count > 0) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No API abstraction defined\n");
|
||||
}
|
||||
end:
|
||||
if (xml)
|
||||
switch_xml_free(xml);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
Called when the system shuts down
|
||||
Macro expands to: switch_status_t mod_abstraction_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_abstraction_shutdown)
|
||||
{
|
||||
/* Cleanup dynamically allocated config settings */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -1386,6 +1386,9 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
switch_time_t t_agent_answered = 0;
|
||||
switch_time_t t_member_called = atoi(h->member_joined_epoch);
|
||||
switch_event_t *event = NULL;
|
||||
char agent_uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
||||
|
||||
switch_uuid_str(agent_uuid_str, sizeof(agent_uuid_str));
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.threads++;
|
||||
@@ -1415,6 +1418,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Type", h->agent_type);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid_str);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-UUID", h->member_uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
|
||||
@@ -1436,10 +1440,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "loopback_bowout", "false");
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "loopback_bowout_on_execute", "false");
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "ignore_early_media", "true");
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "origination_uuid", "%s", agent_uuid_str);
|
||||
|
||||
t_agent_called = local_epoch_time_now(NULL);
|
||||
dialstr = switch_mprintf("%s", h->originate_string);
|
||||
status = switch_ivr_originate(NULL, &agent_session, &cause, dialstr, 60, NULL, h->member_cid_name, h->member_cid_number, NULL, ovars, SOF_NONE, NULL);
|
||||
|
||||
switch_safe_free(dialstr);
|
||||
|
||||
switch_event_destroy(&ovars);
|
||||
@@ -1473,7 +1479,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Invalid agent type '%s' for agent '%s', aborting member offering", h->agent_type, h->agent_name);
|
||||
status = SWITCH_CAUSE_USER_NOT_REGISTERED;
|
||||
cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
|
||||
}
|
||||
|
||||
/* Originate/Bridge is not finished, processing the return value */
|
||||
|
||||
@@ -4791,11 +4791,10 @@ SWITCH_STANDARD_API(system_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Executing command: %s\n", cmd);
|
||||
if (switch_system(cmd, SWITCH_TRUE) < 0) {
|
||||
if (switch_stream_system(cmd, stream) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd);
|
||||
}
|
||||
stream->write_function(stream, "+OK\n");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -312,6 +312,10 @@ typedef struct conference_obj {
|
||||
uint32_t eflags;
|
||||
uint32_t verbose_events;
|
||||
int end_count;
|
||||
/* allow extra time after 'endconf' member leaves */
|
||||
switch_time_t endconf_time;
|
||||
int endconf_grace_time;
|
||||
|
||||
uint32_t relationship_total;
|
||||
uint32_t score;
|
||||
int mux_loop_count;
|
||||
@@ -364,6 +368,7 @@ struct conference_member {
|
||||
switch_codec_t read_codec;
|
||||
switch_codec_t write_codec;
|
||||
char *rec_path;
|
||||
switch_time_t rec_time;
|
||||
uint8_t *frame;
|
||||
uint8_t *last_frame;
|
||||
uint32_t frame_size;
|
||||
@@ -900,7 +905,9 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
||||
conference->count++;
|
||||
|
||||
if (switch_test_flag(member, MFLAG_ENDCONF)) {
|
||||
if (conference->end_count++) {};
|
||||
if (conference->end_count++) {
|
||||
conference->endconf_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
conference_send_presence(conference);
|
||||
@@ -966,10 +973,6 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
||||
}
|
||||
}
|
||||
|
||||
if (conference->count == 1) {
|
||||
conference->floor_holder = member;
|
||||
}
|
||||
|
||||
if (conference->min && conference->count >= conference->min) {
|
||||
switch_set_flag(conference, CFLAG_ENFORCE_MIN);
|
||||
}
|
||||
@@ -1098,6 +1101,14 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
|
||||
|
||||
if (member == member->conference->floor_holder) {
|
||||
member->conference->floor_holder = NULL;
|
||||
|
||||
if (test_eflag(conference, EFLAG_FLOOR_CHANGE)) {
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", member->id);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
member->conference = NULL;
|
||||
@@ -1107,7 +1118,8 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
|
||||
|
||||
if (switch_test_flag(member, MFLAG_ENDCONF)) {
|
||||
if (!--conference->end_count) {
|
||||
switch_set_flag_locked(conference, CFLAG_DESTRUCT);
|
||||
//switch_set_flag_locked(conference, CFLAG_DESTRUCT);
|
||||
conference->endconf_time = switch_epoch_time_now(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1127,10 +1139,6 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
|
||||
}
|
||||
}
|
||||
|
||||
if (conference->count == 1) {
|
||||
conference->floor_holder = conference->members;
|
||||
}
|
||||
|
||||
if (test_eflag(conference, EFLAG_DEL_MEMBER) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
@@ -1160,20 +1168,30 @@ static void *SWITCH_THREAD_FUNC conference_video_bridge_thread_run(switch_thread
|
||||
switch_status_t status;
|
||||
switch_frame_t *read_frame;
|
||||
conference_obj_t *conference = vh->member_a->conference;
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
switch_thread_rwlock_rdlock(conference->rwlock);
|
||||
switch_thread_rwlock_rdlock(vh->member_a->rwlock);
|
||||
switch_thread_rwlock_rdlock(vh->member_b->rwlock);
|
||||
|
||||
|
||||
|
||||
/* Acquire locks for both sessions so the helper object and member structures don't get destroyed before we exit */
|
||||
switch_core_session_read_lock(session_a);
|
||||
switch_core_session_read_lock(session_b);
|
||||
|
||||
/* Tell the channel to request a fresh vid frame */
|
||||
msg.from = __FILE__;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
|
||||
|
||||
vh->up = 1;
|
||||
while (vh->up == 1 && switch_test_flag(vh->member_a, MFLAG_RUNNING) && switch_test_flag(vh->member_b, MFLAG_RUNNING) &&
|
||||
switch_channel_ready(channel_a) && switch_channel_ready(channel_b)) {
|
||||
|
||||
if (switch_channel_test_flag(channel_a, CF_VIDEO_REFRESH_REQ)) {
|
||||
switch_core_session_receive_message(session_b, &msg);
|
||||
switch_channel_clear_flag(channel_a, CF_VIDEO_REFRESH_REQ);
|
||||
}
|
||||
|
||||
status = switch_core_session_read_video_frame(session_a, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
@@ -1208,21 +1226,25 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr
|
||||
conference_member_t *imember;
|
||||
switch_frame_t *vid_frame;
|
||||
switch_status_t status;
|
||||
int has_vid = 1;// req_iframe = 0;
|
||||
int has_vid = 1, want_refresh = 0;
|
||||
int yield = 0;
|
||||
uint32_t last_member = 0;
|
||||
switch_core_session_t *session;
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
conference->video_running = 1;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video thread started for conference %s\n", conference->name);
|
||||
|
||||
/* Tell the channel to request a fresh vid frame */
|
||||
msg.from = __FILE__;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
|
||||
|
||||
while (has_vid && conference->video_running == 1 && globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) {
|
||||
if (yield) {
|
||||
switch_yield(yield);
|
||||
yield = 0;
|
||||
}
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
switch_mutex_lock(conference->mutex);
|
||||
|
||||
if (!conference->floor_holder) {
|
||||
yield = 100000;
|
||||
@@ -1236,70 +1258,48 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr
|
||||
|
||||
session = conference->floor_holder->session;
|
||||
switch_core_session_read_lock(session);
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
status = switch_core_session_read_video_frame(session, &vid_frame, SWITCH_IO_FLAG_NONE, 0);
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
if (!switch_channel_ready(switch_core_session_get_channel(session))) {
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
status = switch_core_session_read_video_frame(session, &vid_frame, SWITCH_IO_FLAG_NONE, 0);
|
||||
}
|
||||
switch_mutex_lock(conference->mutex);
|
||||
switch_core_session_rwunlock(session);
|
||||
|
||||
if (!SWITCH_READ_ACCEPTABLE(status) || !conference->floor_holder || switch_test_flag(vid_frame, SFF_CNG)) {
|
||||
conference->floor_holder = NULL;
|
||||
//req_iframe = 0;
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
yield = 100000;
|
||||
goto do_continue;
|
||||
}
|
||||
|
||||
if (conference->floor_holder->id != last_member) {
|
||||
int iframe = 0;
|
||||
#if 0
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
|
||||
if (!req_iframe) {
|
||||
/* Tell the channel to request a fresh vid frame */
|
||||
msg.from = __FILE__;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
|
||||
switch_core_session_receive_message(conference->floor_holder->session, &msg);
|
||||
req_iframe = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vid_frame->codec->implementation->ianacode == 34) { /* h.263 */
|
||||
//iframe = (*((int16_t *) vid_frame->data) >> 12 == 6);
|
||||
iframe = 1;
|
||||
} else if (vid_frame->codec->implementation->ianacode == 115) { /* h.263-1998 */
|
||||
int y = *((int8_t *) vid_frame->data + 2) & 0xfe;
|
||||
iframe = (y == 0x80 || y == 0x82);
|
||||
} else if (vid_frame->codec->implementation->ianacode == 99) { /* h.264 */
|
||||
uint8_t * hdr = vid_frame->data;
|
||||
uint8_t fragment_type = hdr[0] & 0x1f;
|
||||
uint8_t nal_type = hdr[1] & 0x1f;
|
||||
uint8_t start_bit = hdr[1] & 0x80;
|
||||
iframe = (((fragment_type == 28 || fragment_type == 29) && nal_type == 5 && start_bit == 128) || fragment_type == 5);
|
||||
} else { /* we need more defs */
|
||||
iframe = 1;
|
||||
}
|
||||
|
||||
if (!iframe) {
|
||||
goto do_continue;
|
||||
}
|
||||
|
||||
//req_iframe = 0;
|
||||
}
|
||||
|
||||
last_member = conference->floor_holder->id;
|
||||
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
switch_mutex_lock(conference->mutex);
|
||||
has_vid = 0;
|
||||
want_refresh = 0;
|
||||
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
if (imember->session && switch_channel_test_flag(switch_core_session_get_channel(imember->session), CF_VIDEO)) {
|
||||
switch_channel_t *ichannel = switch_core_session_get_channel(imember->session);
|
||||
|
||||
if (switch_channel_test_flag(ichannel, CF_VIDEO_REFRESH_REQ)) {
|
||||
want_refresh++;
|
||||
switch_channel_clear_flag(ichannel, CF_VIDEO_REFRESH_REQ);
|
||||
}
|
||||
|
||||
if (imember->session && switch_channel_test_flag(ichannel, CF_VIDEO)) {
|
||||
has_vid++;
|
||||
switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (want_refresh) {
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
want_refresh = 0;
|
||||
}
|
||||
|
||||
do_continue:
|
||||
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
do_continue:
|
||||
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video thread ending for conference %s\n", conference->name);
|
||||
@@ -1353,8 +1353,8 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
int has_file_data = 0, members_with_video = 0;
|
||||
uint32_t conf_energy = 0;
|
||||
int nomoh = 0;
|
||||
conference_member_t *video_bridge_members[2] = { 0 };
|
||||
|
||||
conference_member_t *floor_holder, *video_bridge_members[2] = { 0 };
|
||||
|
||||
/* Sync the conference to a single timing source */
|
||||
if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_set_flag(conference, CFLAG_DESTRUCT);
|
||||
@@ -1364,18 +1364,26 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
switch_mutex_lock(conference->mutex);
|
||||
has_file_data = ready = total = 0;
|
||||
|
||||
|
||||
floor_holder = conference->floor_holder;
|
||||
|
||||
/* Read one frame of audio from each member channel and save it for redistribution */
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
uint32_t buf_read = 0;
|
||||
total++;
|
||||
imember->read = 0;
|
||||
|
||||
if (imember->session) {
|
||||
if (switch_channel_test_flag(switch_core_session_get_channel(imember->session), CF_VIDEO)) {
|
||||
if (switch_test_flag(imember, MFLAG_RUNNING) && imember->session) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(imember->session);
|
||||
|
||||
if ((!floor_holder || (imember->score_iir > SCORE_IIR_SPEAKING_MAX && (floor_holder->score_iir < SCORE_IIR_SPEAKING_MIN))) &&
|
||||
(!switch_test_flag(conference, CFLAG_VID_FLOOR) || switch_channel_test_flag(channel, CF_VIDEO))) {
|
||||
floor_holder = imember;
|
||||
}
|
||||
|
||||
if (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_VIDEO)) {
|
||||
members_with_video++;
|
||||
|
||||
if (switch_test_flag(imember, MFLAG_VIDEO_BRIDGE)) {
|
||||
if (switch_test_flag(conference, CFLAG_VIDEO_BRIDGE) && switch_test_flag(imember, MFLAG_VIDEO_BRIDGE)) {
|
||||
if (!video_bridge_members[0]) {
|
||||
video_bridge_members[0] = imember;
|
||||
} else {
|
||||
@@ -1400,6 +1408,48 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
}
|
||||
switch_mutex_unlock(imember->audio_in_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (floor_holder != conference->floor_holder) {
|
||||
switch_event_t *event = NULL;
|
||||
|
||||
if (test_eflag(conference, EFLAG_FLOOR_CHANGE)) {
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
|
||||
|
||||
if (floor_holder) {
|
||||
conference_add_event_member_data(floor_holder, event);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", floor_holder->id);
|
||||
} else {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
|
||||
}
|
||||
|
||||
if (conference->floor_holder) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", conference->floor_holder->id);
|
||||
} else {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Old-ID", "none");
|
||||
}
|
||||
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
if (floor_holder) {
|
||||
switch_channel_t *floor_channel = switch_core_session_get_channel(floor_holder->session);
|
||||
if (switch_channel_test_flag(floor_channel, CF_VIDEO)) {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
msg.from = __FILE__;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
|
||||
|
||||
switch_core_session_receive_message(floor_holder->session, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
conference->floor_holder = floor_holder;
|
||||
}
|
||||
|
||||
|
||||
if (conference->perpetual_sound && !conference->async_fnode) {
|
||||
conference_play_file(conference, conference->perpetual_sound, CONF_DEFAULT_LEADIN, NULL, 1);
|
||||
@@ -1437,6 +1487,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Auto recording file: %s\n", rfile);
|
||||
launch_conference_record_thread(conference, rfile);
|
||||
if (rfile != conference->auto_record) {
|
||||
conference->record_filename = switch_core_strdup(conference->pool, rfile);
|
||||
switch_safe_free(rfile);
|
||||
} else {
|
||||
conference->record_filename = switch_core_strdup(conference->pool, conference->auto_record);
|
||||
@@ -1459,7 +1510,16 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
}
|
||||
}
|
||||
|
||||
if (conference->vh[0].up != 1 && conference->vh[1].up != 1 && video_bridge_members[0] && video_bridge_members[1]){
|
||||
if (conference->vh[0].up == 0 &&
|
||||
conference->vh[1].up == 0 &&
|
||||
video_bridge_members[0] &&
|
||||
video_bridge_members[1] &&
|
||||
switch_test_flag(video_bridge_members[0], MFLAG_RUNNING) &&
|
||||
switch_test_flag(video_bridge_members[1], MFLAG_RUNNING) &&
|
||||
switch_channel_ready(switch_core_session_get_channel(video_bridge_members[0]->session)) &&
|
||||
switch_channel_ready(switch_core_session_get_channel(video_bridge_members[1]->session))
|
||||
) {
|
||||
|
||||
launch_conference_video_bridge_thread(video_bridge_members[0], video_bridge_members[1]);
|
||||
}
|
||||
}
|
||||
@@ -1693,6 +1753,13 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
}
|
||||
|
||||
if (!conference->end_count && conference->endconf_time &&
|
||||
switch_epoch_time_now(NULL) - conference->endconf_time > conference->endconf_grace_time) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Conference %s: endconf grace time exceeded (%u)\n",
|
||||
conference->name, conference->endconf_grace_time);
|
||||
switch_set_flag(conference, CFLAG_DESTRUCT);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
}
|
||||
/* Rinse ... Repeat */
|
||||
@@ -2386,7 +2453,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
||||
switch_frame_t *read_frame = NULL;
|
||||
uint32_t hangover = 40, hangunder = 5, hangover_hits = 0, hangunder_hits = 0, diff_level = 400;
|
||||
switch_core_session_t *session = member->session;
|
||||
int check_floor_change;
|
||||
|
||||
switch_assert(member != NULL);
|
||||
|
||||
@@ -2400,7 +2466,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
||||
and mux it with any audio from other channels. */
|
||||
|
||||
while (switch_test_flag(member, MFLAG_RUNNING) && switch_channel_ready(channel)) {
|
||||
check_floor_change = 0;
|
||||
|
||||
if (switch_channel_ready(channel) && switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
|
||||
switch_yield(100000);
|
||||
@@ -2541,7 +2606,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
||||
}
|
||||
|
||||
if (diff >= diff_level || ++hangunder_hits >= hangunder) {
|
||||
check_floor_change = 1;
|
||||
|
||||
hangover_hits = hangunder_hits = 0;
|
||||
member->last_talking = switch_epoch_time_now(NULL);
|
||||
@@ -2642,27 +2706,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
||||
|
||||
switch_mutex_unlock(member->read_mutex);
|
||||
|
||||
if (check_floor_change) {
|
||||
switch_mutex_lock(member->conference->member_mutex);
|
||||
if ((!member->conference->floor_holder ||
|
||||
!switch_test_flag(member->conference->floor_holder, MFLAG_TALKING) ||
|
||||
((member->score_iir > SCORE_IIR_SPEAKING_MAX) && (member->conference->floor_holder->score_iir < SCORE_IIR_SPEAKING_MIN))) &&
|
||||
(!switch_test_flag(member->conference, CFLAG_VID_FLOOR) || switch_channel_test_flag(channel, CF_VIDEO))) {
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_FLOOR_CHANGE) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d",
|
||||
member->conference->floor_holder ? member->conference->floor_holder->id : 0);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", member->conference->floor_holder ? member->id : 0);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
member->conference->floor_holder = member;
|
||||
}
|
||||
switch_mutex_unlock(member->conference->member_mutex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3167,6 +3210,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
|
||||
member->conference = conference;
|
||||
member->native_rate = conference->rate;
|
||||
member->rec_path = rec->path;
|
||||
member->rec_time = switch_epoch_time_now(NULL);
|
||||
fh.channels = 1;
|
||||
fh.samplerate = conference->rate;
|
||||
member->id = next_member_id();
|
||||
@@ -4411,6 +4455,11 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
|
||||
switch_xml_set_attr_d(x_conference, "recording", "true");
|
||||
}
|
||||
|
||||
if (conference->endconf_grace_time > 0) {
|
||||
switch_snprintf(i, sizeof(i), "%u", conference->endconf_grace_time);
|
||||
switch_xml_set_attr_d(x_conference, "endconf_grace_time", ival);
|
||||
}
|
||||
|
||||
switch_snprintf(i, sizeof(i), "%d", switch_epoch_time_now(NULL) - conference->run_time);
|
||||
switch_xml_set_attr_d(x_conference, "run_time", ival);
|
||||
|
||||
@@ -4436,6 +4485,22 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
|
||||
char tmp[50] = "";
|
||||
|
||||
if (switch_test_flag(member, MFLAG_NOCHANNEL)) {
|
||||
if (member->rec_path) {
|
||||
x_member = switch_xml_add_child_d(x_members, "member", moff++);
|
||||
switch_assert(x_member);
|
||||
switch_xml_set_attr_d(x_member, "type", "recording_node");
|
||||
/* or:
|
||||
x_member = switch_xml_add_child_d(x_members, "recording_node", moff++);
|
||||
*/
|
||||
|
||||
x_tag = switch_xml_add_child_d(x_member, "record_path", count++);
|
||||
switch_xml_set_txt_d(x_tag, member->rec_path);
|
||||
|
||||
x_tag = switch_xml_add_child_d(x_member, "join_time", count++);
|
||||
switch_xml_set_attr_d(x_tag, "type", "UNIX-epoch");
|
||||
switch_snprintf(i, sizeof(i), "%d", member->rec_time);
|
||||
switch_xml_set_txt_d(x_tag, i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -5164,6 +5229,93 @@ static switch_status_t conf_api_sub_pin(conference_obj_t *conference, switch_str
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t conf_api_sub_get(conference_obj_t *conference,
|
||||
switch_stream_handle_t *stream, int argc, char **argv) {
|
||||
int ret_status = SWITCH_STATUS_GENERR;
|
||||
|
||||
if (argc != 3) {
|
||||
ret_status = SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
ret_status = SWITCH_STATUS_SUCCESS;
|
||||
if (strcasecmp(argv[2], "run_time") == 0) {
|
||||
stream->write_function(stream, "%ld",
|
||||
switch_epoch_time_now(NULL) - conference->run_time);
|
||||
} else if (strcasecmp(argv[2], "count") == 0) {
|
||||
stream->write_function(stream, "%d",
|
||||
conference->count);
|
||||
} else if (strcasecmp(argv[2], "max_members") == 0) {
|
||||
stream->write_function(stream, "%d",
|
||||
conference->max_members);
|
||||
} else if (strcasecmp(argv[2], "rate") == 0) {
|
||||
stream->write_function(stream, "%d",
|
||||
conference->rate);
|
||||
} else if (strcasecmp(argv[2], "profile_name") == 0) {
|
||||
stream->write_function(stream, "%s",
|
||||
conference->profile_name);
|
||||
} else if (strcasecmp(argv[2], "sound_prefix") == 0) {
|
||||
stream->write_function(stream, "%s",
|
||||
conference->sound_prefix);
|
||||
} else if (strcasecmp(argv[2], "caller_id_name") == 0) {
|
||||
stream->write_function(stream, "%s",
|
||||
conference->caller_id_name);
|
||||
} else if (strcasecmp(argv[2], "caller_id_number") == 0) {
|
||||
stream->write_function(stream, "%s",
|
||||
conference->caller_id_number);
|
||||
} else if (strcasecmp(argv[2], "is_locked") == 0) {
|
||||
stream->write_function(stream, "%s",
|
||||
switch_test_flag(conference, CFLAG_LOCKED) ? "locked" : "");
|
||||
} else if (strcasecmp(argv[2], "endconf_grace_time") == 0) {
|
||||
stream->write_function(stream, "%d",
|
||||
conference->endconf_grace_time);
|
||||
} else {
|
||||
ret_status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_status;
|
||||
}
|
||||
|
||||
static switch_status_t conf_api_sub_set(conference_obj_t *conference,
|
||||
switch_stream_handle_t *stream, int argc, char **argv) {
|
||||
int ret_status = SWITCH_STATUS_GENERR;
|
||||
|
||||
if (argc != 4 || zstr(argv[3])) {
|
||||
ret_status = SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
ret_status = SWITCH_STATUS_SUCCESS;
|
||||
if (strcasecmp(argv[2], "max_members") == 0) {
|
||||
int new_max = atoi(argv[3]);
|
||||
if (new_max >= 0) {
|
||||
stream->write_function(stream, "%d", conference->max_members);
|
||||
conference->max_members = new_max;
|
||||
} else {
|
||||
ret_status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
} else if (strcasecmp(argv[2], "sound_prefix") == 0) {
|
||||
stream->write_function(stream, "%s",conference->sound_prefix);
|
||||
conference->sound_prefix = switch_core_strdup(conference->pool, argv[3]);
|
||||
} else if (strcasecmp(argv[2], "caller_id_name") == 0) {
|
||||
stream->write_function(stream, "%s",conference->caller_id_name);
|
||||
conference->caller_id_name = switch_core_strdup(conference->pool, argv[3]);
|
||||
} else if (strcasecmp(argv[2], "caller_id_number") == 0) {
|
||||
stream->write_function(stream, "%s",conference->caller_id_number);
|
||||
conference->caller_id_number = switch_core_strdup(conference->pool, argv[3]);
|
||||
} else if (strcasecmp(argv[2], "endconf_grace_time") == 0) {
|
||||
int new_gt = atoi(argv[3]);
|
||||
if (new_gt >= 0) {
|
||||
stream->write_function(stream, "%d", conference->endconf_grace_time);
|
||||
conference->endconf_grace_time = new_gt;
|
||||
} else {
|
||||
ret_status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
} else {
|
||||
ret_status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_status;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
CONF_API_COMMAND_LIST = 0,
|
||||
CONF_API_COMMAND_ENERGY,
|
||||
@@ -5189,12 +5341,16 @@ typedef enum {
|
||||
CONF_API_COMMAND_NORECORD,
|
||||
CONF_API_COMMAND_EXIT_SOUND,
|
||||
CONF_API_COMMAND_ENTER_SOUND,
|
||||
CONF_API_COMMAND_PIN,
|
||||
CONF_API_COMMAND_NOPIN,
|
||||
CONF_API_COMMAND_GET,
|
||||
CONF_API_COMMAND_SET,
|
||||
} api_command_type_t;
|
||||
|
||||
/* API Interface Function sub-commands */
|
||||
/* Entries in this list should be kept in sync with the enum above */
|
||||
static api_command_t conf_api_sub_commands[] = {
|
||||
{"list", (void_fn_t) & conf_api_sub_list, CONF_API_SUB_ARGS_SPLIT, "list", "[delim <string>]"},
|
||||
{"list", (void_fn_t) & conf_api_sub_list, CONF_API_SUB_ARGS_SPLIT, "list", "[delim <string>]|[count]"},
|
||||
{"xml_list", (void_fn_t) & conf_api_sub_xml_list, CONF_API_SUB_ARGS_SPLIT, "xml_list", ""},
|
||||
{"energy", (void_fn_t) & conf_api_sub_energy, CONF_API_SUB_MEMBER_TARGET, "energy", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
{"volume_in", (void_fn_t) & conf_api_sub_volume_in, CONF_API_SUB_MEMBER_TARGET, "volume_in", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
@@ -5224,6 +5380,8 @@ static api_command_t conf_api_sub_commands[] = {
|
||||
{"enter_sound", (void_fn_t) & conf_api_sub_enter_sound, CONF_API_SUB_ARGS_SPLIT, "enter_sound", "on|off|none|file <filename>"},
|
||||
{"pin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "pin", "<pin#>"},
|
||||
{"nopin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "nopin", ""},
|
||||
{"get", (void_fn_t) & conf_api_sub_get, CONF_API_SUB_ARGS_SPLIT, "get", "<parameter-name>"},
|
||||
{"set", (void_fn_t) & conf_api_sub_set, CONF_API_SUB_ARGS_SPLIT, "set", "<parameter-name> <value>"},
|
||||
};
|
||||
|
||||
#define CONFFUNCAPISIZE (sizeof(conf_api_sub_commands)/sizeof(conf_api_sub_commands[0]))
|
||||
@@ -6244,7 +6402,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
uint32_t max_members_val;
|
||||
errno = 0; /* sanity first */
|
||||
max_members_val = strtol(max_members_str, NULL, 0); /* base 0 lets 0x... for hex 0... for octal and base 10 otherwise through */
|
||||
if (errno == ERANGE || errno == EINVAL || max_members_val < 0 || max_members_val == 1) {
|
||||
if (errno == ERANGE || errno == EINVAL || (int32_t) max_members_val < 0 || max_members_val == 1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"conference_max_members variable %s is invalid, not setting a limit\n", max_members_str);
|
||||
} else {
|
||||
@@ -6791,6 +6949,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
||||
char *auto_record = NULL;
|
||||
char *conference_log_dir = NULL;
|
||||
char *terminate_on_silence = NULL;
|
||||
char *endconf_grace_time = NULL;
|
||||
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH+1];
|
||||
switch_uuid_t uuid;
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
@@ -6974,7 +7133,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
||||
} else if (!strcasecmp(var, "max-members") && !zstr(val)) {
|
||||
errno = 0; /* sanity first */
|
||||
max_members = strtol(val, NULL, 0); /* base 0 lets 0x... for hex 0... for octal and base 10 otherwise through */
|
||||
if (errno == ERANGE || errno == EINVAL || max_members < 0 || max_members == 1) {
|
||||
if (errno == ERANGE || errno == EINVAL || (int32_t) max_members < 0 || max_members == 1) {
|
||||
/* a negative wont work well, and its foolish to have a conference limited to 1 person unless the outbound
|
||||
* stuff is added, see comments above
|
||||
*/
|
||||
@@ -6998,6 +7157,8 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
||||
auto_record = val;
|
||||
} else if (!strcasecmp(var, "terminate-on-silence") && !zstr(val)) {
|
||||
terminate_on_silence = val;
|
||||
} else if (!strcasecmp(var, "endconf-grace-time") && !zstr(val)) {
|
||||
endconf_grace_time = val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7222,9 +7383,12 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
||||
if (!zstr(auto_record)) {
|
||||
conference->auto_record = switch_core_strdup(conference->pool, auto_record);
|
||||
}
|
||||
if (!zstr(terminate_on_silence)) {
|
||||
conference->terminate_on_silence = atoi(terminate_on_silence);
|
||||
}
|
||||
if (!zstr(terminate_on_silence)) {
|
||||
conference->terminate_on_silence = atoi(terminate_on_silence);
|
||||
}
|
||||
if (!zstr(endconf_grace_time)) {
|
||||
conference->endconf_grace_time = atoi(endconf_grace_time);
|
||||
}
|
||||
|
||||
if (!zstr(verbose_events) && switch_true(verbose_events)) {
|
||||
conference->verbose_events = 1;
|
||||
|
||||
@@ -597,7 +597,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_db_load)
|
||||
switch_api_interface_t *commands_api_interface;
|
||||
switch_limit_interface_t *limit_interface;
|
||||
|
||||
memset(&globals, 0, sizeof(&globals));
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
strncpy(globals.hostname, switch_core_get_switchname(), sizeof(globals.hostname));
|
||||
globals.pool = pool;
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ static struct {
|
||||
char *dbname;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
char odbc_dsn[1024];
|
||||
char *odbc_user;
|
||||
char *odbc_pass;
|
||||
} globals;
|
||||
|
||||
#define DIR_PROFILE_CONFIGITEM_COUNT 100
|
||||
@@ -187,24 +190,51 @@ char *string_to_keypad_digit(const char *in)
|
||||
return dst;
|
||||
}
|
||||
|
||||
switch_cache_db_handle_t *directory_get_db_handle(void)
|
||||
{
|
||||
switch_cache_db_connection_options_t options = { {0} };
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
|
||||
if (!zstr(globals.odbc_dsn)) {
|
||||
options.odbc_options.dsn = globals.odbc_dsn;
|
||||
options.odbc_options.user = globals.odbc_user;
|
||||
options.odbc_options.pass = globals.odbc_pass;
|
||||
|
||||
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS) {
|
||||
dbh = NULL;
|
||||
}
|
||||
return dbh;
|
||||
} else {
|
||||
options.core_db_options.db_path = globals.dbname;
|
||||
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_CORE_DB, &options) != SWITCH_STATUS_SUCCESS) {
|
||||
dbh = NULL;
|
||||
}
|
||||
return dbh;
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t directory_execute_sql(char *sql, switch_mutex_t *mutex)
|
||||
{
|
||||
switch_core_db_t *db;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (mutex) {
|
||||
switch_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
if (!(db = switch_core_db_open_file(globals.dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", globals.dbname);
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
if (!(dbh = directory_get_db_handle())) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
|
||||
goto end;
|
||||
}
|
||||
status = switch_core_db_persistant_execute(db, sql, 1);
|
||||
switch_core_db_close(db);
|
||||
|
||||
end:
|
||||
if (globals.debug > 1) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "sql: %s\n", sql);
|
||||
|
||||
status = switch_cache_db_execute_sql(dbh, sql, NULL);
|
||||
|
||||
end:
|
||||
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
|
||||
if (mutex) {
|
||||
switch_mutex_unlock(mutex);
|
||||
}
|
||||
@@ -417,7 +447,9 @@ static dir_profile_t *load_profile(const char *profile_name)
|
||||
|
||||
static switch_status_t load_config(switch_bool_t reload)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_xml_t cfg, xml = NULL, settings, param, x_profiles, x_profile;
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||
@@ -430,6 +462,22 @@ static switch_status_t load_config(switch_bool_t reload)
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
|
||||
if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
|
||||
if (switch_odbc_available()) {
|
||||
switch_set_string(globals.odbc_dsn, val);
|
||||
if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) {
|
||||
*globals.odbc_user++ = '\0';
|
||||
if ((globals.odbc_pass = strchr(globals.odbc_user, ':'))) {
|
||||
*globals.odbc_pass++ = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
|
||||
}
|
||||
} else if (!strcasecmp(var, "dbname") && !zstr(val)) {
|
||||
globals.dbname = switch_core_strdup(globals.pool, val);
|
||||
}
|
||||
|
||||
if (!strcasecmp(var, "debug")) {
|
||||
globals.debug = atoi(val);
|
||||
}
|
||||
@@ -441,10 +489,27 @@ static switch_status_t load_config(switch_bool_t reload)
|
||||
load_profile(switch_xml_attr_soft(x_profile, "name"));
|
||||
}
|
||||
}
|
||||
|
||||
if (zstr(globals.odbc_dsn) && zstr(globals.dbname)) {
|
||||
globals.dbname = switch_core_sprintf(globals.pool, "directory");
|
||||
}
|
||||
|
||||
dbh = directory_get_db_handle();
|
||||
if (dbh) {
|
||||
if (!reload) {
|
||||
switch_cache_db_test_reactive(dbh, "delete from directory_search where uuid != '' and name_visible != '' ", "drop table directory_search", dir_sql);
|
||||
}
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!2\n");
|
||||
status = SWITCH_STATUS_TERM;
|
||||
goto end;
|
||||
}
|
||||
end:
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_xml_free(xml);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
static dir_profile_t *get_profile(const char *profile_name)
|
||||
@@ -579,7 +644,7 @@ static switch_status_t populate_database(switch_core_session_t *session, dir_pro
|
||||
}
|
||||
}
|
||||
sql = switch_mprintf("BEGIN;%s;COMMIT;", sqlvalues);
|
||||
directory_execute_sql(sql, profile->mutex);
|
||||
directory_execute_sql(sql, globals.mutex);
|
||||
|
||||
end:
|
||||
switch_safe_free(sql);
|
||||
@@ -755,7 +820,7 @@ switch_status_t navigate_entrys(switch_core_session_t *session, dir_profile_t *p
|
||||
globals.hostname, switch_core_session_get_uuid(session), (params->search_by_last_name ? "last_name_digit" : "first_name_digit"),
|
||||
params->digits);
|
||||
|
||||
directory_execute_sql_callback(profile->mutex, sql, sql2str_callback, &cbt);
|
||||
directory_execute_sql_callback(globals.mutex, sql, sql2str_callback, &cbt);
|
||||
switch_safe_free(sql);
|
||||
|
||||
result_count = atoi(entry_count);
|
||||
@@ -786,7 +851,7 @@ switch_status_t navigate_entrys(switch_core_session_t *session, dir_profile_t *p
|
||||
listing_cbt.index = 0;
|
||||
listing_cbt.want = cur_entry;
|
||||
listing_cbt.move = ENTRY_MOVE_NEXT;
|
||||
directory_execute_sql_callback(profile->mutex, sql, listing_callback, &listing_cbt);
|
||||
directory_execute_sql_callback(globals.mutex, sql, listing_callback, &listing_cbt);
|
||||
status = listen_entry(session, profile, &listing_cbt);
|
||||
if (!zstr(listing_cbt.transfer_to)) {
|
||||
switch_copy_string(params->transfer_to, listing_cbt.transfer_to, 255);
|
||||
@@ -937,7 +1002,7 @@ SWITCH_STANDARD_APP(directory_function)
|
||||
|
||||
/* Delete all sql entry for this call */
|
||||
sql = switch_mprintf("delete from directory_search where hostname = '%q' and uuid = '%q'", globals.hostname, switch_core_session_get_uuid(session));
|
||||
directory_execute_sql(sql, profile->mutex);
|
||||
directory_execute_sql(sql, globals.mutex);
|
||||
switch_safe_free(sql);
|
||||
profile_rwunlock(profile);
|
||||
}
|
||||
@@ -946,8 +1011,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_directory_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_status_t status;
|
||||
switch_core_db_t *db = NULL;
|
||||
char *sql = NULL;
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
globals.pool = pool;
|
||||
@@ -964,20 +1027,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_directory_load)
|
||||
|
||||
globals.hostname = switch_core_get_switchname();
|
||||
|
||||
globals.dbname = switch_core_sprintf(pool, "directory");
|
||||
|
||||
if ((db = switch_core_db_open_file(globals.dbname))) {
|
||||
switch_core_db_test_reactive(db, "select count(uuid),name_visible from directory_search", "drop table directory_search", dir_sql);
|
||||
switch_core_db_close(db);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open db name : %s\n", globals.dbname);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("delete from directory_search where hostname = '%q'", globals.hostname);
|
||||
directory_execute_sql(sql, globals.mutex);
|
||||
switch_safe_free(sql);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "directory", "directory", DIR_DESC, directory_function, DIR_USAGE, SAF_NONE);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
|
||||
@@ -340,18 +340,13 @@ static void bind_to_session(switch_core_session_t *session,
|
||||
uint32_t digit_timeout = 1500;
|
||||
uint32_t input_timeout = 0;
|
||||
const char *var;
|
||||
uint32_t tmp;
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "bind_digit_digit_timeout"))) {
|
||||
tmp = (uint32_t) atol(var);
|
||||
if (tmp < 0) tmp = 0;
|
||||
digit_timeout = tmp;
|
||||
digit_timeout = switch_atoul(var);
|
||||
}
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "bind_digit_input_timeout"))) {
|
||||
tmp = (uint32_t) atol(var);
|
||||
if (tmp < 0) tmp = 0;
|
||||
input_timeout = tmp;
|
||||
input_timeout = switch_atoul(var);
|
||||
}
|
||||
|
||||
switch_ivr_dmachine_create(&dmachine, "DPTOOLS", NULL, digit_timeout, input_timeout, NULL, digit_nomatch_action_callback, session);
|
||||
@@ -495,7 +490,7 @@ SWITCH_STANDARD_APP(play_and_detect_speech_function)
|
||||
char *engine = argv[0];
|
||||
char *grammar = argv[1];
|
||||
char *result = NULL;
|
||||
switch_ivr_play_and_detect_speech(session, file, engine, grammar, &result);
|
||||
switch_ivr_play_and_detect_speech(session, file, engine, grammar, &result, 0, NULL);
|
||||
switch_channel_set_variable(channel, "detect_speech_result", result);
|
||||
} else {
|
||||
/* bad input */
|
||||
@@ -1570,6 +1565,22 @@ SWITCH_STANDARD_API(strepoch_api_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_API(strmicroepoch_api_function)
|
||||
{
|
||||
switch_time_t out;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
out = switch_micro_time_now();
|
||||
} else {
|
||||
out = switch_str_time(cmd);
|
||||
}
|
||||
|
||||
stream->write_function(stream, "%"SWITCH_TIME_T_FMT, out);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(strftime_api_function)
|
||||
{
|
||||
switch_size_t retsize;
|
||||
@@ -2217,10 +2228,7 @@ SWITCH_STANDARD_APP(read_function)
|
||||
}
|
||||
|
||||
if (argc > 6) {
|
||||
digit_timeout = atoi(argv[6]);
|
||||
if (digit_timeout < 0) {
|
||||
digit_timeout = 0;
|
||||
}
|
||||
digit_timeout = switch_atoui(argv[6]);
|
||||
}
|
||||
|
||||
if (min_digits <= 1) {
|
||||
@@ -2303,10 +2311,7 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
|
||||
}
|
||||
|
||||
if (argc > 9) {
|
||||
digit_timeout = atoi(argv[9]);
|
||||
if (digit_timeout < 0) {
|
||||
digit_timeout = 0;
|
||||
}
|
||||
digit_timeout = switch_atoui(argv[9]);
|
||||
}
|
||||
|
||||
if (argc > 10) {
|
||||
@@ -2589,25 +2594,16 @@ SWITCH_STANDARD_APP(record_function)
|
||||
l++;
|
||||
}
|
||||
if (l) {
|
||||
limit = atoi(l);
|
||||
if (limit < 0) {
|
||||
limit = 0;
|
||||
}
|
||||
limit = switch_atoui(l);
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[2]) {
|
||||
fh.thresh = atoi(argv[2]);
|
||||
if (fh.thresh < 0) {
|
||||
fh.thresh = 0;
|
||||
}
|
||||
fh.thresh = switch_atoui(argv[2]);
|
||||
}
|
||||
|
||||
if (argv[3]) {
|
||||
fh.silence_hits = atoi(argv[3]);
|
||||
if (fh.silence_hits < 0) {
|
||||
fh.silence_hits = 0;
|
||||
}
|
||||
fh.silence_hits = switch_atoui(argv[3]);
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "record_rate"))) {
|
||||
@@ -3481,9 +3477,7 @@ SWITCH_STANDARD_APP(wait_for_silence_function)
|
||||
listen_hits = atoi(argv[2]);
|
||||
|
||||
if (argv[3]) {
|
||||
if ((timeout_ms = atoi(argv[3])) < 0) {
|
||||
timeout_ms = 0;
|
||||
}
|
||||
timeout_ms = switch_atoui(argv[3]);
|
||||
}
|
||||
|
||||
if (thresh > 0 && silence_hits > 0 && listen_hits > 0) {
|
||||
@@ -4006,6 +4000,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_CHAT(chat_interface, "api", api_chat_send);
|
||||
|
||||
SWITCH_ADD_API(api_interface, "strepoch", "Convert a date string into epoch time", strepoch_api_function, "<string>");
|
||||
SWITCH_ADD_API(api_interface, "strmicroepoch", "Convert a date string into micoepoch time", strmicroepoch_api_function, "<string>");
|
||||
SWITCH_ADD_API(api_interface, "chat", "chat", chat_api_function, "<proto>|<from>|<to>|<message>|[<content-type>]");
|
||||
SWITCH_ADD_API(api_interface, "strftime", "strftime", strftime_api_function, "<format_string>");
|
||||
SWITCH_ADD_API(api_interface, "presence", "presence", presence_api_function, PRESENCE_USAGE);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
BASE=../../../..
|
||||
|
||||
ESL_DIR = $(switch_srcdir)/libs/esl
|
||||
|
||||
LOCAL_LDFLAGS=-L$(ESL_DIR) -lesl
|
||||
LOCAL_OBJS=$(ESL_DIR)/libesl.so
|
||||
LOCAL_LIBADD=$(ESL_DIR)/libesl.so
|
||||
LOCAL_CFLAGS=-I$(ESL_DIR)/src/include
|
||||
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
$(ESL_DIR)/libesl.so: $(ESL_DIR)/Makefile
|
||||
cd $(ESL_DIR) && $(MAKE) -j1
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* mod_esl.c -- Allow to generate remote ESL commands
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include <esl.h>
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_esl_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_esl_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_esl_load);
|
||||
|
||||
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
|
||||
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
|
||||
*/
|
||||
SWITCH_MODULE_DEFINITION(mod_esl, mod_esl_load, mod_esl_shutdown, NULL);
|
||||
|
||||
SWITCH_STANDARD_API(single_esl_api_function)
|
||||
{
|
||||
esl_handle_t handle = {{0}};
|
||||
char *host = "127.0.0.1";
|
||||
char *s_port = NULL;
|
||||
int port = 8021;
|
||||
char *username = NULL;
|
||||
char *password = "ClueCon";
|
||||
char *args = NULL;
|
||||
char *s_timeout = NULL;
|
||||
int timeout = 5000;
|
||||
char *dup = strdup(cmd);
|
||||
char *send = NULL;
|
||||
|
||||
username = dup;
|
||||
|
||||
if (username && (password = strchr(username, '|'))) {
|
||||
*password++ = '\0';
|
||||
}
|
||||
|
||||
if (password && (host = strchr(password, ' '))) {
|
||||
*host++ = '\0';
|
||||
}
|
||||
|
||||
if (host && (s_timeout = strchr(host, ' '))) {
|
||||
*s_timeout++ = '\0';
|
||||
}
|
||||
|
||||
if (host && (s_port = strchr(host, ':'))) {
|
||||
*s_port++ = '\0';
|
||||
}
|
||||
|
||||
if (s_timeout && (args = strchr(s_timeout, ' '))) {
|
||||
*args++ = '\0';
|
||||
}
|
||||
|
||||
if (!zstr(s_port)) {
|
||||
port = atoi(s_port);
|
||||
}
|
||||
|
||||
if (zstr(host) || zstr(password) || zstr(args) || zstr(s_timeout)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad parameters\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
timeout = atoi(s_timeout);
|
||||
|
||||
|
||||
if (esl_connect_timeout(&handle, host, port, username, password, timeout) != ESL_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to connect to remote ESL at %s:%d\n",
|
||||
host, port);
|
||||
goto end;
|
||||
} else {
|
||||
send = switch_mprintf("api %s", args);
|
||||
if (esl_send_recv_timed(&handle, send, timeout) != ESL_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Disconnected from remote ESL at %s:%d\n",
|
||||
host, port);
|
||||
goto end;
|
||||
} else {
|
||||
stream->write_function(stream, handle.last_sr_event->body);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
esl_disconnect(&handle);
|
||||
memset(&handle, 0, sizeof(handle));
|
||||
switch_safe_free(send);
|
||||
switch_safe_free(dup);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Macro expands to: switch_status_t mod_esl_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_esl_load)
|
||||
{
|
||||
switch_api_interface_t *api_interface;
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_API(api_interface, "single_esl", "Allow to do a single connection api call to a remote ESL server", single_esl_api_function, "[<user>]|<password> <host>[:<port>] <timeout> <remote api> <arguments>");
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
Called when the system shuts down
|
||||
Macro expands to: switch_status_t mod_esl_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_esl_shutdown)
|
||||
{
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -488,6 +488,7 @@ struct fifo_chime_data {
|
||||
char *orbit_exten;
|
||||
char *orbit_dialplan;
|
||||
char *orbit_context;
|
||||
char *exit_key;
|
||||
};
|
||||
|
||||
typedef struct fifo_chime_data fifo_chime_data_t;
|
||||
@@ -521,25 +522,25 @@ static switch_status_t caller_read_frame_callback(switch_core_session_t *session
|
||||
if (cd->list[cd->index]) {
|
||||
switch_input_args_t args = { 0 };
|
||||
char buf[25] = "";
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
const char *caller_exit_key = switch_channel_get_variable(channel, "fifo_caller_exit_key");
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
switch_status_t status;
|
||||
|
||||
args.input_callback = moh_on_dtmf;
|
||||
args.buf = buf;
|
||||
args.buflen = sizeof(buf);
|
||||
args.read_frame_callback = chime_read_frame_callback;
|
||||
args.user_data = user_data;
|
||||
|
||||
|
||||
status = switch_ivr_play_file(session, NULL, cd->list[cd->index], &args);
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
if (match_key(caller_exit_key, *buf)) {
|
||||
|
||||
if (match_key(cd->exit_key, *buf)) {
|
||||
cd->abort = 1;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
cd->next = switch_epoch_time_now(NULL) + cd->freq;
|
||||
cd->index++;
|
||||
}
|
||||
@@ -2485,6 +2486,7 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
cd.total = switch_separate_string(list_dup, ',', cd.list, (sizeof(cd.list) / sizeof(cd.list[0])));
|
||||
cd.freq = freq;
|
||||
cd.next = switch_epoch_time_now(NULL) + cd.freq;
|
||||
cd.exit_key = (char *) switch_channel_get_variable(channel, "fifo_caller_exit_key");
|
||||
}
|
||||
|
||||
send_presence(node);
|
||||
@@ -2492,6 +2494,7 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
while (switch_channel_ready(channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
char buf[25] = "";
|
||||
switch_status_t rstatus;
|
||||
|
||||
args.input_callback = moh_on_dtmf;
|
||||
args.buf = buf;
|
||||
@@ -2514,13 +2517,14 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
switch_core_session_flush_private_events(session);
|
||||
|
||||
if (moh) {
|
||||
switch_status_t status = switch_ivr_play_file(session, NULL, moh, &args);
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
aborted = 1;
|
||||
goto abort;
|
||||
}
|
||||
rstatus = switch_ivr_play_file(session, NULL, moh, &args);
|
||||
} else {
|
||||
switch_ivr_collect_digits_callback(session, &args, 0, 0);
|
||||
rstatus = switch_ivr_collect_digits_callback(session, &args, 0, 0);
|
||||
}
|
||||
|
||||
if (!SWITCH_READ_ACCEPTABLE(rstatus)) {
|
||||
aborted = 1;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (match_key(caller_exit_key, *buf)) {
|
||||
|
||||
@@ -111,9 +111,15 @@ SWITCH_STANDARD_APP(record_fsv_function)
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
switch_dtmf_t dtmf = { 0 };
|
||||
int count = 0, sanity = 30;
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
/* Tell the channel to request a fresh vid frame */
|
||||
msg.from = __FILE__;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
switch_channel_answer(channel);
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
|
||||
switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, "");
|
||||
|
||||
@@ -290,6 +296,13 @@ SWITCH_STANDARD_APP(play_fsv_function)
|
||||
switch_dtmf_t dtmf = { 0 };
|
||||
switch_frame_t *read_frame;
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
/* Tell the channel to request a fresh vid frame */
|
||||
msg.from = __FILE__;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
|
||||
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
@@ -370,6 +383,8 @@ SWITCH_STANDARD_APP(play_fsv_function)
|
||||
}
|
||||
switch_core_session_set_read_codec(session, &codec);
|
||||
|
||||
switch_core_service_session_av(session, SWITCH_FALSE, SWITCH_TRUE);
|
||||
|
||||
while (switch_channel_ready(channel)) {
|
||||
|
||||
if (read(fd, &bytes, sizeof(bytes)) != sizeof(bytes)) {
|
||||
@@ -440,6 +455,8 @@ SWITCH_STANDARD_APP(play_fsv_function)
|
||||
|
||||
}
|
||||
|
||||
switch_core_thread_session_end(session);
|
||||
|
||||
switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "OK");
|
||||
|
||||
end:
|
||||
|
||||
@@ -974,7 +974,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)
|
||||
switch_limit_interface_t *limit_interface;
|
||||
switch_status_t status;
|
||||
|
||||
memset(&globals, 0, sizeof(&globals));
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
globals.pool = pool;
|
||||
|
||||
status = switch_event_reserve_subclass(LIMIT_EVENT_USAGE);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
$xml = new XMLWriter();
|
||||
$xml->openMemory();
|
||||
$xml->setIndent(1);
|
||||
$xml->startDocument();
|
||||
|
||||
if ( $_REQUEST['exiting'] ) {
|
||||
header('Content-Type: text/plain');
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
header('Content-Type: text/xml');
|
||||
$xml->startElement('document');
|
||||
$xml->writeAttribute('type', 'xml/freeswitch-httapi');
|
||||
|
||||
$xml->startElement('work');
|
||||
|
||||
$xml->startElement('pause');
|
||||
$xml->writeAttribute('milliseconds', '1500');
|
||||
$xml->endElement(); // </pause>
|
||||
|
||||
$xml->startElement('playback');
|
||||
$xml->writeAttribute('name', 'digits');
|
||||
$xml->writeAttribute('file', 'http://sidious.freeswitch.org/sounds/exten.wav');
|
||||
$xml->writeAttribute('error-file', 'http://sidious.freeswitch.org/sounds/invalid.wav');
|
||||
$xml->writeAttribute('input-timeout', '5000');
|
||||
$xml->writeAttribute('action', 'dial:default:XML');
|
||||
|
||||
$xml->startElement("bind");
|
||||
$xml->writeAttribute('strip',"#");
|
||||
$xml->text("~\\d+\#");
|
||||
$xml->endElement(); // </bind>
|
||||
$xml->endElement(); // </playback>
|
||||
|
||||
$xml->endElement(); // </work>
|
||||
$xml->endElement(); // </document>
|
||||
|
||||
print $xml->outputMemory();
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
if ( array_key_exists( 'session_id', $_REQUEST ) ) {
|
||||
session_id( $_REQUEST['session_id'] );
|
||||
}
|
||||
session_start();
|
||||
|
||||
$xml = new XMLWriter();
|
||||
$xml->openMemory();
|
||||
$xml->setIndent(1);
|
||||
$xml->startDocument();
|
||||
|
||||
if ( array_key_exists( 'exten', $_REQUEST ) ) {
|
||||
$exten = $_REQUEST['exten'];
|
||||
} elseif ( array_key_exists( 'exten', $_SESSION ) ) {
|
||||
$exten = $_SESSION['exten'];
|
||||
} else {
|
||||
$exten = '';
|
||||
}
|
||||
|
||||
if ( array_key_exists( 'pin', $_REQUEST ) ) {
|
||||
$pin = $_REQUEST['pin'];
|
||||
} elseif ( array_key_exists( 'pin', $_SESSION ) ) {
|
||||
$pin = $_SESSION['pin'];
|
||||
} else {
|
||||
$pin = '';
|
||||
}
|
||||
|
||||
if ( array_key_exists( 'exiting', $_REQUEST ) ) {
|
||||
$exiting = $_REQUEST['exiting'];
|
||||
} elseif ( array_key_exists( 'exiting', $_SESSION ) ) {
|
||||
$exiting = $_SESSION['exiting'];
|
||||
} else {
|
||||
$exiting = '';
|
||||
}
|
||||
|
||||
if ( $exiting ) {
|
||||
header('Content-Type: text/plain');
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
header('Content-Type: text/xml');
|
||||
$xml->startElement('document');
|
||||
$xml->writeAttribute('type', 'xml/freeswitch-httapi');
|
||||
|
||||
if ( $exten && $pin ) {
|
||||
$xml->startElement('work');
|
||||
$xml->writeElement("playback", "http://sidious.freeswitch.org/sounds/ext_num.wav");
|
||||
|
||||
$xml->startElement("say");
|
||||
$xml->writeAttribute('language', "en");
|
||||
$xml->writeAttribute('type', "name_spelled");
|
||||
$xml->writeAttribute('method', "pronounced");
|
||||
$xml->text($exten);
|
||||
$xml->endElement(); // </say>
|
||||
|
||||
$xml->startElement('pause');
|
||||
$xml->writeAttribute('milliseconds', "1500");
|
||||
$xml->endElement(); // </pause>
|
||||
|
||||
$xml->startElement("say");
|
||||
$xml->writeAttribute('language', "en");
|
||||
$xml->writeAttribute('type', "name_spelled");
|
||||
$xml->writeAttribute('method', "pronounced");
|
||||
$xml->text($pin);
|
||||
$xml->endElement(); // </say>
|
||||
|
||||
$xml->writeElement('hangup');
|
||||
$xml->endElement(); // </work>
|
||||
} elseif ( $exten ) {
|
||||
$_SESSION['exten'] = $exten;
|
||||
|
||||
$xml->startElement('work');
|
||||
$xml->startElement('playback');
|
||||
$xml->writeAttribute('name', "pin");
|
||||
$xml->writeAttribute('file', "http://sidious.freeswitch.org/sounds/pin.wav");
|
||||
$xml->writeAttribute('error-file', "http://sidious.freeswitch.org/sounds/bad-pin.wav");
|
||||
$xml->writeAttribute('input-timeout', "5000");
|
||||
|
||||
$xml->startElement("bind");
|
||||
$xml->writeAttribute('strip', "#");
|
||||
$xml->text("~\\d+\#");
|
||||
$xml->endElement(); // </bind>
|
||||
|
||||
$xml->endElement(); // </playback>
|
||||
$xml->endElement(); // </work>
|
||||
} else {
|
||||
$xml->startElement('work');
|
||||
|
||||
$xml->startElement('playback');
|
||||
$xml->writeAttribute('name', "exten");
|
||||
$xml->writeAttribute('file', "http://sidious.freeswitch.org/sounds/exten.wav");
|
||||
$xml->writeAttribute('loops', "3");
|
||||
$xml->writeAttribute('error-file', "http://sidious.freeswitch.org/sounds/invalid.wav");
|
||||
$xml->writeAttribute('input-timeout', "5000");
|
||||
|
||||
$xml->startElement("bind");
|
||||
$xml->writeAttribute('strip', "#");
|
||||
$xml->text("~\\d+\#");
|
||||
$xml->endElement(); // </bind>
|
||||
|
||||
$xml->endElement(); // </playback>
|
||||
$xml->endElement(); // </work>
|
||||
}
|
||||
|
||||
$xml->endElement(); // </document>
|
||||
|
||||
print $xml->outputMemory();
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
if ( array_key_exists( 'session_id', $_REQUEST ) ) {
|
||||
session_id( $_REQUEST['session_id'] );
|
||||
}
|
||||
session_start();
|
||||
|
||||
$xml = new XMLWriter();
|
||||
$xml->openMemory();
|
||||
$xml->setIndent(1);
|
||||
$xml->startDocument();
|
||||
|
||||
if ( array_key_exists( 'exiting', $_REQUEST ) ) {
|
||||
$exiting = $_REQUEST['exiting'];
|
||||
} elseif ( array_key_exists( 'exiting', $_SESSION ) ) {
|
||||
$exiting = $_SESSION['exiting'];
|
||||
} else {
|
||||
$exiting = '';
|
||||
}
|
||||
|
||||
if ( $_FILES && array_key_exists( 'recorded_file', $_FILES ) ) {
|
||||
move_uploaded_file($_FILES['recorded_file']['tmp_name'], '/tmp/' . $_FILES['recorded_file']['name']);
|
||||
trigger_error( print_r( $_FILES, true ) );
|
||||
|
||||
header('Content-Type: text/plain');
|
||||
print "OK\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
if ( $exiting ) {
|
||||
header('Content-Type: text/plain');
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
header('Content-Type: text/xml');
|
||||
$xml->startElement('document');
|
||||
$xml->writeAttribute('type', 'xml/freeswitch-httapi');
|
||||
|
||||
$xml->startElement('work');
|
||||
|
||||
$xml->startElement('pause');
|
||||
$xml->writeAttribute('milliseconds', "1500");
|
||||
$xml->endElement();
|
||||
|
||||
$xml->startElement('playback');
|
||||
$xml->writeAttribute('file', "http://sidious.freeswitch.org/eg/ivr-say_name.wav");
|
||||
$xml->endElement();
|
||||
|
||||
$xml->startElement('record');
|
||||
$xml->writeAttribute('name', "recorded_file");
|
||||
$xml->writeAttribute('file', $_REQUEST['session_id'] . ".wav");
|
||||
$xml->writeAttribute('error-file', "http://sidious.freeswitch.org/sounds/invalid.wav");
|
||||
$xml->writeAttribute('input-timeout', "5000");
|
||||
$xml->writeAttribute('beep-file', "tone_stream://%(1000,0,460)");
|
||||
$xml->endElement();
|
||||
|
||||
$xml->startElement("bind");
|
||||
$xml->writeAttribute('strip', "#");
|
||||
$xml->text("~\\d+\#");
|
||||
$xml->endElement();
|
||||
|
||||
|
||||
|
||||
$xml->endElement(); // </work>
|
||||
|
||||
$xml->endElement(); // </document>
|
||||
|
||||
print $xml->outputMemory();
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
if ( array_key_exists( 'session_id', $_REQUEST ) ) {
|
||||
session_id( $_REQUEST['session_id'] );
|
||||
}
|
||||
session_start();
|
||||
|
||||
$xml = new XMLWriter();
|
||||
$xml->openMemory();
|
||||
$xml->setIndent(1);
|
||||
$xml->startDocument();
|
||||
|
||||
if ( array_key_exists( 'exiting', $_REQUEST ) ) {
|
||||
$exiting = $_REQUEST['exiting'];
|
||||
} elseif ( array_key_exists( 'exiting', $_SESSION ) ) {
|
||||
$exiting = $_SESSION['exiting'];
|
||||
} else {
|
||||
$exiting = '';
|
||||
}
|
||||
|
||||
if ( array_key_exists( 'result', $_REQUEST ) ) {
|
||||
$result = $_REQUEST['result'];
|
||||
} elseif ( array_key_exists( 'result', $_SESSION ) ) {
|
||||
$result = $_SESSION['result'];
|
||||
} else {
|
||||
$result = '';
|
||||
}
|
||||
|
||||
if ( array_key_exists( 'input_type', $_REQUEST ) ) {
|
||||
$input_type = $_REQUEST['input_type'];
|
||||
} elseif ( array_key_exists( 'input_type', $_SESSION ) ) {
|
||||
$input_type = $_SESSION['input_type'];
|
||||
} else {
|
||||
$input_type = '';
|
||||
}
|
||||
|
||||
if ( $exiting ) {
|
||||
header('Content-Type: text/plain');
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
header('Content-Type: text/xml');
|
||||
$xml->startElement('document');
|
||||
$xml->writeAttribute('type', 'xml/freeswitch-httapi');
|
||||
|
||||
if ($result) {
|
||||
$xml->startElement('work');
|
||||
|
||||
if ($type == "dtmf") {
|
||||
$xml->startElement("say");
|
||||
$xml->writeAttribute('language', "en");
|
||||
$xml->writeAttribute('type', "name_spelled");
|
||||
$xml->writeAttribute('method', "pronounced");
|
||||
$xml->text( $result );
|
||||
}
|
||||
|
||||
$xml->startElement("log");
|
||||
$xml->writeAttribute('level', "crit");
|
||||
$xml->text($result);
|
||||
$xml->endElement();
|
||||
|
||||
$xml->writeElement('hangup');
|
||||
$xml->endElement();
|
||||
} else {
|
||||
$xml->startElement('work');
|
||||
|
||||
$xml->startElement('pause');
|
||||
$xml->writeAttribute('milliseconds', "1500");
|
||||
$xml->endElement();
|
||||
|
||||
$xml->startElement('playback');
|
||||
$xml->writeAttribute('name', "result");
|
||||
$xml->writeAttribute('asr-engine', "pocketsphinx");
|
||||
$xml->writeAttribute('asr-grammar', "pizza_yesno");
|
||||
$xml->writeAttribute('file', "http://sidious.freeswitch.org/sounds/ConfirmDelivery.wav");
|
||||
$xml->writeAttribute('error-file', "http://sidious.freeswitch.org/sounds/invalid.wav");
|
||||
|
||||
$xml->startElement("bind");
|
||||
$xml->writeAttribute('strip', "#");
|
||||
$xml->text("~\\d+\#");
|
||||
$xml->endElement();
|
||||
|
||||
$xml->endElement();
|
||||
|
||||
$xml->endElement();
|
||||
}
|
||||
|
||||
$xml->endElement(); // </document>
|
||||
|
||||
print $xml->outputMemory();
|
||||
|
||||
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Object initialization:
|
||||
use XML::Simple;
|
||||
use CGI;
|
||||
use Data::Dumper;
|
||||
use XML::Writer;
|
||||
|
||||
my $q = CGI->new;
|
||||
my $exiting = $q->param("exiting");
|
||||
|
||||
if ($exiting) {
|
||||
print $q->header(-type => "text/plain");
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
print $q->header(-type => "text/xml");
|
||||
|
||||
|
||||
my $writer = new XML::Writer(OUTPUT => STDOUT, DATA_MODE => 1);
|
||||
|
||||
$writer->startTag('document', type => 'xml/freeswitch-httapi');
|
||||
|
||||
$writer->startTag('work');
|
||||
$writer->emptyTag('pause', milliseconds => "500");
|
||||
$writer->emptyTag('execute', application => "info");
|
||||
$writer->dataElement('execute', "user_busy", application => "hangup");
|
||||
$writer->endTag('work');
|
||||
|
||||
|
||||
$writer->endTag('document');
|
||||
$writer->end();
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Object initialization:
|
||||
use XML::Simple;
|
||||
use CGI;
|
||||
use Data::Dumper;
|
||||
use XML::Writer;
|
||||
|
||||
my $q = CGI->new;
|
||||
my $exiting = $q->param("exiting");
|
||||
|
||||
if ($exiting) {
|
||||
print $q->header(-type => "text/plain");
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
print $q->header(-type => "text/xml");
|
||||
|
||||
|
||||
my $writer = new XML::Writer(OUTPUT => STDOUT, DATA_MODE => 1);
|
||||
|
||||
$writer->startTag('document', type => 'xml/freeswitch-httapi');
|
||||
|
||||
$writer->startTag('work');
|
||||
$writer->emptyTag('pause', milliseconds => "1500");
|
||||
$writer->startTag('playback',
|
||||
name => digits,
|
||||
file => "http://sidious.freeswitch.org/sounds/exten.wav",
|
||||
'error-file' => "http://sidious.freeswitch.org/sounds/invalid.wav",
|
||||
'input-timeout' => "5000",
|
||||
action => "dial:default:XML");
|
||||
|
||||
$writer->dataElement("bind", "~\\d+\#", strip => "#");
|
||||
$writer->endTag('playback');
|
||||
$writer->endTag('work');
|
||||
|
||||
|
||||
$writer->endTag('document');
|
||||
$writer->end();
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Object initialization:
|
||||
use XML::Simple;
|
||||
use CGI;
|
||||
use Data::Dumper;
|
||||
use XML::Writer;
|
||||
|
||||
my $q = CGI->new;
|
||||
|
||||
my $exten = $q->param("exten");
|
||||
my $pin = $q->param("pin");
|
||||
my $exiting = $q->param("exiting");
|
||||
|
||||
if ($exiting) {
|
||||
print $q->header(-type => "text/plain");
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
print $q->header(-type => "text/xml");
|
||||
|
||||
my $writer = new XML::Writer(OUTPUT => STDOUT, DATA_MODE => 1);
|
||||
|
||||
$writer->startTag('document', type => 'xml/freeswitch-httapi');
|
||||
|
||||
$writer->startTag('params');
|
||||
if ($exten) {
|
||||
$writer->dataElement("exten", $exten);
|
||||
}
|
||||
if ($pin) {
|
||||
$writer->dataElement("exten", $pin);
|
||||
}
|
||||
$writer->endTag('params');
|
||||
|
||||
if ($exten eq "invalid" || $pin eq "invalid") {
|
||||
$writer->startTag('work');
|
||||
$writer->emptyTag('hangup', cause => "destination_out_of_order");
|
||||
$writer->endTag('work');
|
||||
}
|
||||
|
||||
if ($exten && $pin) {
|
||||
$writer->startTag('work');
|
||||
$writer->dataElement("playback", "http://sidious.freeswitch.org/sounds/ext_num.wav");
|
||||
$writer->dataElement("say", $exten, language => "en", type => "name_spelled", method => "pronounced");
|
||||
$writer->emptyTag('pause', milliseconds => "1500");
|
||||
$writer->dataElement("say", $pin, language => "en", type => "name_spelled", method => "pronounced");
|
||||
$writer->emptyTag('hangup');
|
||||
$writer->endTag('work');
|
||||
} elsif ($exten) {
|
||||
$writer->startTag('work');
|
||||
$writer->startTag('playback',
|
||||
name => "pin",
|
||||
file => "http://sidious.freeswitch.org/sounds/pin.wav",
|
||||
'error-file' => "http://sidious.freeswitch.org/sounds/bad-pin.wav",
|
||||
'input-timeout' => "5000");
|
||||
|
||||
|
||||
$writer->dataElement("bind", "~\\d+\#", strip => "#");
|
||||
$writer->endTag('playback');
|
||||
$writer->endTag('work');
|
||||
} else {
|
||||
$writer->startTag('work');
|
||||
$writer->startTag('playback',
|
||||
name => "exten",
|
||||
file => "http://sidious.freeswitch.org/sounds/exten.wav",
|
||||
loops => "3",
|
||||
'error-file' => "http://sidious.freeswitch.org/sounds/invalid.wav",
|
||||
'input-timeout' => "5000");
|
||||
|
||||
$writer->dataElement("bind", "~\\d+\#", strip => "#");
|
||||
$writer->endTag('playback');
|
||||
$writer->endTag('work');
|
||||
}
|
||||
|
||||
$writer->endTag('document');
|
||||
$writer->end();
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Object initialization:
|
||||
use XML::Simple;
|
||||
use CGI;
|
||||
use Data::Dumper;
|
||||
use XML::Writer;
|
||||
|
||||
my $q = CGI->new;
|
||||
my $exiting = $q->param("exiting");
|
||||
|
||||
my $file = $q->upload("recorded_file");
|
||||
|
||||
if ($file) {
|
||||
open(O, ">/tmp/recording.wav");
|
||||
while(<$file>) {
|
||||
print O $_;
|
||||
}
|
||||
close O;
|
||||
|
||||
print $q->header(-type => "text/plain");
|
||||
print "OK\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($exiting) {
|
||||
print $q->header(-type => "text/plain");
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
print $q->header(-type => "text/xml");
|
||||
|
||||
my $writer = new XML::Writer(OUTPUT => STDOUT, DATA_MODE => 1);
|
||||
|
||||
$writer->startTag('document', type => 'xml/freeswitch-httapi');
|
||||
|
||||
$writer->startTag('work');
|
||||
$writer->emptyTag('pause', milliseconds => "1500");
|
||||
$writer->emptyTag('playback', file => "http://sidious.freeswitch.org/eg/ivr-say_name.wav");
|
||||
$writer->startTag('record',
|
||||
name => "recorded_file",
|
||||
file => "recording.wav",
|
||||
'error-file' => "http://sidious.freeswitch.org/sounds/invalid.wav",
|
||||
'input-timeout' => "5000",
|
||||
'beep-file', => "tone_stream://%(1000,0,460)");
|
||||
|
||||
|
||||
$writer->dataElement("bind", "~\\d+\#", strip => "#");
|
||||
$writer->endTag('record');
|
||||
|
||||
$writer->endTag('work');
|
||||
|
||||
|
||||
$writer->endTag('document');
|
||||
$writer->end();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Object initialization:
|
||||
use XML::Simple;
|
||||
use CGI;
|
||||
use Data::Dumper;
|
||||
use XML::Writer;
|
||||
|
||||
my $q = CGI->new;
|
||||
|
||||
my $result = $q->param("result");
|
||||
my $type = $q->param("input_type");
|
||||
my $exiting = $q->param("exiting");
|
||||
|
||||
if ($exiting) {
|
||||
print $q->header(-type => "text/plain");
|
||||
print "OK";
|
||||
exit();
|
||||
}
|
||||
|
||||
print $q->header(-type => "text/xml");
|
||||
|
||||
|
||||
my $writer = new XML::Writer(OUTPUT => STDOUT, DATA_MODE => 1);
|
||||
|
||||
$writer->startTag('document', type => 'xml/freeswitch-httapi');
|
||||
|
||||
if ($result) {
|
||||
$writer->startTag('work');
|
||||
|
||||
if ($type eq "dtmf") {
|
||||
$writer->dataElement("say", $result, language => "en", type => "name_spelled", method => "pronounced");
|
||||
}
|
||||
|
||||
$writer->dataElement("log", $result, level => "crit");
|
||||
|
||||
$writer->emptyTag('hangup');
|
||||
$writer->endTag('work');
|
||||
} else {
|
||||
|
||||
$writer->startTag('work');
|
||||
$writer->emptyTag('pause', milliseconds => "1500");
|
||||
$writer->startTag('playback',
|
||||
name => "result",
|
||||
'asr-engine' => "pocketsphinx",
|
||||
'asr-grammar' => "pizza_yesno",
|
||||
file => "http://sidious.freeswitch.org/sounds/ConfirmDelivery.wav",
|
||||
'error-file' => "http://sidious.freeswitch.org/sounds/invalid.wav"
|
||||
);
|
||||
|
||||
$writer->dataElement("bind", "~\\d+\#", strip => "#");
|
||||
#$writer->dataElement("bind", "1");
|
||||
#$writer->dataElement("bind", "2");
|
||||
$writer->endTag('playback');
|
||||
|
||||
$writer->endTag('work');
|
||||
}
|
||||
|
||||
$writer->endTag('document');
|
||||
$writer->end();
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<configuration name="httapi.conf" description="HT-TAPI Hypertext Telephony API">
|
||||
<settings>
|
||||
<!-- print xml on the consol -->
|
||||
<param name="debug" value="true"/>
|
||||
<!-- time to keep audio files when discoverd they were deleted from the http server -->
|
||||
<param name="file-not-found-expires" value="300"/>
|
||||
<!-- how often to re-check the server to make sure the remote file has not changed -->
|
||||
<param name="file-cache-ttl" value="300"/>
|
||||
</settings>
|
||||
<profiles>
|
||||
<profile name="default">
|
||||
|
||||
<!-- default params for conference action tags -->
|
||||
<conference>
|
||||
<param name="default-profile" value="default"/>
|
||||
</conference>
|
||||
|
||||
<!-- default params for dial action tags -->
|
||||
<dial>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
</dial>
|
||||
|
||||
<!-- permissions -->
|
||||
<permissions>
|
||||
<!-- <permission name="all" value="true"/> -->
|
||||
<!--<permission name="none" value="true"/> -->
|
||||
<permission name="set-params" value="true"/>
|
||||
<permission name="set-vars" value="false">
|
||||
<!-- default to "deny" or "allow" -->
|
||||
<!-- type attr can be "deny" or "allow" nothing defaults to opposite of the list default so allow in this case -->
|
||||
<!--
|
||||
<variable-list default="deny">
|
||||
<variable name="caller_id_name"/>
|
||||
<variable name="hangup"/>
|
||||
</variable-list>
|
||||
-->
|
||||
</permission>
|
||||
<permission name="get-vars" value="false">
|
||||
<!-- default to "deny" or "allow" -->
|
||||
<!-- type attr can be "deny" or "allow" nothing defaults to opposite of the list default so allow in this case -->
|
||||
<!--
|
||||
<variable-list default="deny">
|
||||
<variable name="caller_id_name"/>
|
||||
<variable name="hangup"/>
|
||||
</variable-list>
|
||||
-->
|
||||
</permission>
|
||||
<permission name="extended-data" value="false"/>
|
||||
<permission name="execute-apps" value="true">
|
||||
<!-- default to "deny" or "allow" -->
|
||||
<application-list default="deny">
|
||||
<!-- type attr can be "deny" or "allow" nothing defaults to opposite of the list default so allow in this case -->
|
||||
<application name="info"/>
|
||||
<application name="hangup"/>
|
||||
</application-list>
|
||||
</permission>
|
||||
<permission name="expand-vars-in-tag-body" value="false">
|
||||
<!-- default to "deny" or "allow" -->
|
||||
<!-- type attr can be "deny" or "allow" nothing defaults to opposite of the list default so allow in this case -->
|
||||
<!--
|
||||
<variable-list default="deny">
|
||||
<variable name="caller_id_name"/>
|
||||
<variable name="hangup"/>
|
||||
</variable-list>
|
||||
|
||||
<api-list default="deny">
|
||||
<api name="expr"/>
|
||||
<api name="lua"/>
|
||||
</api-list>
|
||||
-->
|
||||
</permission>
|
||||
<permission name="dial" value="true"/>
|
||||
<permission name="dial-set-context" value="false"/>
|
||||
<permission name="dial-set-dialplan" value="false"/>
|
||||
<permission name="dial-set-cid-name" value="false"/>
|
||||
<permission name="dial-set-cid-number" value="false"/>
|
||||
<permission name="dial-full-originate" value="false"/>
|
||||
<permission name="conference" value="true"/>
|
||||
<permission name="conference-set-profile" value="false"/>
|
||||
</permissions>
|
||||
|
||||
<params>
|
||||
<!-- default url can be overridden by app data -->
|
||||
<param name="gateway-url" value="http://www.freeswitch.org/api/index.cgi" />
|
||||
|
||||
<!-- set this to provide authentication credentials to the server -->
|
||||
<!--<param name="gateway-credentials" value="muser:mypass"/>-->
|
||||
<!--<param name="auth-scheme" value="basic"/>-->
|
||||
|
||||
<!-- optional: this will enable the CA root certificate check by libcurl to
|
||||
verify that the certificate was issued by a major Certificate Authority.
|
||||
note: default value is disabled. only enable if you want this! -->
|
||||
<!--<param name="enable-cacert-check" value="true"/>-->
|
||||
<!-- optional: verify that the server is actually the one listed in the cert -->
|
||||
<!-- <param name="enable-ssl-verifyhost" value="true"/> -->
|
||||
|
||||
<!-- optional: these options can be used to specify custom SSL certificates
|
||||
to use for HTTPS communications. Either use both options or neither.
|
||||
Specify your public key with 'ssl-cert-path' and the private key with
|
||||
'ssl-key-path'. If your private key has a password, specify it with
|
||||
'ssl-key-password'. -->
|
||||
<!-- <param name="ssl-cert-path" value="$${base_dir}/conf/certs/public_key.pem"/> -->
|
||||
<!-- <param name="ssl-key-path" value="$${base_dir}/conf/certs/private_key.pem"/> -->
|
||||
<!-- <param name="ssl-key-password" value="MyPrivateKeyPassword"/> -->
|
||||
<!-- optional timeout -->
|
||||
<!-- <param name="timeout" value="10"/> -->
|
||||
|
||||
<!-- optional: use a custom CA certificate in PEM format to verify the peer
|
||||
with. This is useful if you are acting as your own certificate authority.
|
||||
note: only makes sense if used in combination with "enable-cacert-check." -->
|
||||
<!-- <param name="ssl-cacert-file" value="$${base_dir}/conf/certs/cacert.pem"/> -->
|
||||
|
||||
<!-- optional: specify the SSL version to force HTTPS to use. Valid options are
|
||||
"SSLv3" and "TLSv1". Otherwise libcurl will auto-negotiate the version. -->
|
||||
<!-- <param name="ssl-version" value="TLSv1"/> -->
|
||||
|
||||
<!-- optional: enables cookies and stores them in the specified file. -->
|
||||
<!-- <param name="cookie-file" value="/tmp/cookie-mod_xml_curl.txt"/> -->
|
||||
|
||||
<!-- one or more of these imply you want to pick the exact variables that are transmitted -->
|
||||
<!--<param name="enable-post-var" value="Unique-ID"/>-->
|
||||
</params>
|
||||
|
||||
</profile>
|
||||
</profiles>
|
||||
</configuration>
|
||||
@@ -0,0 +1,287 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mod_httapi"
|
||||
ProjectGUID="{0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}"
|
||||
RootNamespace="mod_httapi"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\mod_httapi.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>mod_httapi</ProjectName>
|
||||
<ProjectGuid>{4748FF56-CA85-4809-97D6-A94C0FAC1D77}</ProjectGuid>
|
||||
<RootNamespace>mod_httapi</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_httapi.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,325 @@
|
||||
HT-TAPI Hyper-Text Telephony API and http file format plugin
|
||||
|
||||
This module provides an HTTP based Telephony API using a standard FreeSWITCH application interface as well as a cached http file format interface.
|
||||
|
||||
The file format plugin can be used like this:
|
||||
<action application="playback" data="http://some.com/sounds/foo.wav"/>
|
||||
|
||||
This syntax is valid anywhere a filename parameter is requested in FreeSWITCH.
|
||||
|
||||
|
||||
The application is called like this:
|
||||
|
||||
<action application="httapi" data="{url=http://some.host.com/app.cgi}"/>
|
||||
|
||||
The target url is expected to be a CGI returning text/xml using the documentation below.
|
||||
|
||||
The format is roughly as described below (We could use a DTD maybe).
|
||||
|
||||
<document type="xml/freeswitch-httapi">
|
||||
<params>
|
||||
<someparam>someval</someparam>
|
||||
</params>
|
||||
<variables>
|
||||
<somevar>someval</somevar>
|
||||
</variables>
|
||||
<work>
|
||||
<...>
|
||||
</work>
|
||||
</document>
|
||||
|
||||
|
||||
The profile name must be chosen to bind to a preset series of settings and permissions to use as a basis for the client session.
|
||||
It's chosen from the specified params or from the channel variable using the keyname 'httapi_profile' and if not specified will default to 'default'
|
||||
Any params specified in the initial data of the application encased in brackets {} will be parsed into the initial params similar to originate.
|
||||
These params remain set until the call ends and are supplied as form elements on each hit to the HTTP server.
|
||||
If the permissions allow, a <params> tag is parsed from the resulting document and set into this data set and will be mirrored back on subsequqent http posts.
|
||||
Also if the permissions allow a <variables> tag is parsed the same way setting channel variables.
|
||||
The <work> tag is required and contains one or more of the supported command tags that generally manipulate the call behaviour.
|
||||
The application will continue to do the task in the work section until an error is encoutered or when an action from the work tag warrants it.
|
||||
If the session exits the httapi app without hanging up it can do other tasks and make another call to httapi and the session data will remain preserved.
|
||||
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
<document type="xml/freeswitch-httapi">
|
||||
<params></params>
|
||||
<work>
|
||||
<playback name="exten" file="http://my.com/sounds/exten.wav" error-file="http://my.com/sounds/invalid.wav" input-timeout="5000">
|
||||
<bind strip="#">~\d+#</bind>
|
||||
</playback>
|
||||
</work>
|
||||
</document>
|
||||
|
||||
BINDINGS
|
||||
Several of the work tags that indicate they support bindings can contain one of more bind tags that function with similar fashion to bind_digit_action
|
||||
|
||||
<bind action strip>*EXPR*</bind>
|
||||
|
||||
ATTRS:
|
||||
action : a specific url to go to next if the binding is dialed
|
||||
strip : a character to strip from in the result such as #
|
||||
|
||||
WORK TAGS:
|
||||
<work>*ACTIONS*</work>
|
||||
|
||||
|
||||
<playback file name error-file action digit-timeout input-timeout loops asr-engine asr-grammar><bind action strip>*EXPR*</bind></playback>
|
||||
: Plays a file and optionally collects input.
|
||||
|
||||
ATTRS:
|
||||
file : The file
|
||||
name : Param name to save result.
|
||||
error-file : Error file to play on invalid input.
|
||||
action : Change the new target url.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
digit-timeout : Timeout waiting for digits after file plays (when input bindings are present)
|
||||
input-timeout : Timeout waiting for more digits in a multi-digit input.
|
||||
loops : max times to play the file when input bindings are present.
|
||||
asr-engine : ASR engine to use
|
||||
asr-grammar : ASR grammar to use
|
||||
|
||||
|
||||
|
||||
|
||||
<record file name error-file action digit-timeout input-timeout><bind action strip>*EXPR*</bind></record>
|
||||
: Records a file, optionally collects input and posts the file back to the target url.
|
||||
|
||||
ATTRS:
|
||||
file : The file
|
||||
name : Param name to save result.
|
||||
error-file : Error file to play on invalid input.
|
||||
action : Change the new target url.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
digit-timeout : Timeout waiting for digits after file plays (when input bindings are present)
|
||||
input-timeout : Timeout waiting for more digits in a multi-digit input.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<pause name error-file action digit-timeout input-timeout loops milliseconds><bind action strip>*EXPR*</bind></pause>
|
||||
: Waits for input for a specific amount of time.
|
||||
|
||||
ATTRS:
|
||||
milliseconds : Number of milliseconds to pause
|
||||
name : Param name to save result.
|
||||
error-file : Error file to play on invalid input.
|
||||
action : Change the new target url.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
digit-timeout : Timeout waiting for digits after file plays (when input bindings are present)
|
||||
input-timeout : Timeout waiting for more digits in a multi-digit input.
|
||||
loops : max times to play the file when input bindings are present.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<speak file name error-file action digit-timeout input-timeout loops engine voice><bind action strip>*EXPR*</bind></speak>
|
||||
: Read Text to Speech with optional input.
|
||||
|
||||
ATTRS:
|
||||
file : The file
|
||||
name : Param name to save result.
|
||||
error-file : Error file to play on invalid input.
|
||||
action : Change the new target url.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
digit-timeout : Timeout waiting for digits after file plays (when input bindings are present)
|
||||
input-timeout : Timeout waiting for more digits in a multi-digit input.
|
||||
loops : max times to play the file when input bindings are present.
|
||||
engine : tts engine to use.
|
||||
voice : tts voice to use.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<say file name error-file action digit-timeout input-timeout loops language type method gender><bind action strip>*EXPR*</bind></say>
|
||||
: Use the FS say engine to iterate sounds to similate a human speaker.
|
||||
|
||||
ATTRS:
|
||||
file : The file
|
||||
name : Param name to save result.
|
||||
error-file : Error file to play on invalid input.
|
||||
action : Change the new target url.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
digit-timeout : Timeout waiting for digits after file plays (when input bindings are present)
|
||||
input-timeout : Timeout waiting for more digits in a multi-digit input.
|
||||
loops : max times to play the file when input bindings are present.
|
||||
language : language
|
||||
type : type (fs param)
|
||||
method : method (fs param)
|
||||
gender : gender (fs param)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<execute application data action>*DATA*</execute>
|
||||
: Execute a FreeSWITCH app.
|
||||
ATTRS:
|
||||
application : The app to run
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
data : Alternate source for app data
|
||||
*DATA* : The app data
|
||||
|
||||
|
||||
|
||||
<sms to action>DATA</sms>
|
||||
: Send a SMS message.
|
||||
ATTRS:
|
||||
to : The dest number
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
*DATA* : The message data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dial context dialplan caller-id-name caller-id-number action>*DATA*</dial>
|
||||
: Place an outbound call or transfer.
|
||||
|
||||
ATTRS:
|
||||
context : Dialplan context.
|
||||
dialplan : Dialplan dialplan.
|
||||
caller-id-name : Caller ID Name.
|
||||
caller-id-number : Caller ID Number.
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
*DATA* : Number to dial or originate string
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<recordCall limit name action>
|
||||
: begin recording the call. The file will be posted when the call ends.
|
||||
|
||||
ATTRS:
|
||||
limit : Timeout in seconds.
|
||||
name : Name to use for input values.
|
||||
action : URL action to use.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
|
||||
|
||||
|
||||
|
||||
<conference profile action>
|
||||
: Start a conference call.
|
||||
|
||||
ATTRS:
|
||||
profile : Conference profile to use.
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
|
||||
|
||||
|
||||
<hangup cause action>
|
||||
: Hangup the call
|
||||
|
||||
ATTRS:
|
||||
cause : Hangup cause
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
|
||||
|
||||
|
||||
<break>
|
||||
: Exit the httapi application and continue in the dialplan.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<log level clean action>
|
||||
: Write a log line to fs_cli, console, logs, etc.
|
||||
ATTRS:
|
||||
level : The log level to use.
|
||||
clean : If true do not print log prefix.
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
|
||||
<continue action>
|
||||
: Just continue (no-op)
|
||||
|
||||
ATTRS:
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
|
||||
|
||||
<getVar action temp-action permanent/>
|
||||
: Get a Channel variable (depends on permissions)
|
||||
|
||||
ATTRS:
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
permanent : Add as a permanent param or just once.
|
||||
|
||||
|
||||
<voicemail action temp-action check auth-only profile domain id/>
|
||||
: Call the voicemail app without requiring "execute" permissions
|
||||
|
||||
ATTRS:
|
||||
action : Change url to submit to.
|
||||
temp-action : Change url to submit to. just for the next loop.
|
||||
check : true to check (omit to leave)
|
||||
auth-only : authenticate only and move on
|
||||
profile : profile name to use (omit for "default")
|
||||
domain : domain to use (omit for global domain variable)
|
||||
id : id to use (omit to prompt for id)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CONFIGURATION:
|
||||
|
||||
<settings>:
|
||||
<param name="" value="">
|
||||
debug : <true|false> false Print debug data
|
||||
file-cache-ttl : <number of sec> 300 How long to wait before checking the server to see if audio file has changed.
|
||||
file-not-found-expires : <number of sec> 300 How long to still preserve cached audio files that are not found by the server.
|
||||
|
||||
<profile name="<name>"> : CREATE NEW PROFILE TO REFERENCE BY NAME
|
||||
gateway-url : <string> "" Initial URL to connect to.
|
||||
gateway-credentials : <string> "" HTTP credentials.
|
||||
auth-scheme : <string > basic auth scheme to use. [basic|digest|NTLM|GSS-NEGOTIATE|any]
|
||||
disable-100-continue : <true|false> true Disable the 100 continue feature.
|
||||
method : <string> "" METHOD name to send.
|
||||
timeout : <number> 0 Timeout waiting for response.
|
||||
enable-cacert-check : <true|false> false Check CA/CERT.
|
||||
ssl-cert-path : <string> "" path to file.
|
||||
ssl-key-path : <string> "" path to file.
|
||||
ssl-key-password : <string> "" password to use.
|
||||
ssl-version : <string> "" ssl version
|
||||
ssl-cacert-file : <string> "" CA/CERT file.
|
||||
enable-ssl-verifyhost : <true|false> "" Verify ssl host.
|
||||
cookie-file : <string> "" Path to file to use for cookie.
|
||||
enable-post-var : <param_name> "" Specify specifc param names ok to send.
|
||||
bind-local : <string> "" Interface to bind to.
|
||||
default-profile : <string> default Profile to use when not specified.
|
||||
user-agent : <string> mod_httapi/1.0 User Agent header value.
|
||||
|
||||
|
||||
<permissions>: * = default
|
||||
<permission name="" value="">
|
||||
|
||||
*set-params : <params> tag can be parsed for session params.
|
||||
set-vars : <variables> tag can be parsed to set channel vars.
|
||||
extended-data : Extended data is sent like full channel event data.
|
||||
execute-apps : <execute> tag is enabled to execute apps.
|
||||
expand-vars : Allow expansion of FS ${variables}. (this opens up all FSAPI calls)
|
||||
*dial : <dial> tag is enabled allowing outbound dialing.
|
||||
dial-set-context : <dial context=""> context attribute is permitted.
|
||||
dial-set-dialplan : <dial dialplan=""> dialplan attribute is permitted.
|
||||
dial-set-cid-name : <dial cid_name=""> cid_name attribute is permitted.
|
||||
dial-set-cid-number : <dial cid_number=""> cid_number attribute is permitted.
|
||||
dial-full-originate : <dial> full originate syntax is permitted instead of just a number.
|
||||
*conference : <conference> tag is enabled allowing creation of conferences.
|
||||
conference-set-profile : <conference profile=""> attribure is permitted.
|
||||
all : all permissions are set
|
||||
none : no permissions are set
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ SWITCH_STANDARD_API(http_cache_get);
|
||||
SWITCH_STANDARD_API(http_cache_put);
|
||||
SWITCH_STANDARD_API(http_cache_tryget);
|
||||
SWITCH_STANDARD_API(http_cache_clear);
|
||||
SWITCH_STANDARD_API(http_cache_prefetch);
|
||||
|
||||
#define DOWNLOAD_NEEDED "download"
|
||||
|
||||
@@ -148,6 +149,16 @@ struct url_cache {
|
||||
int misses;
|
||||
/** Number of cache errors */
|
||||
int errors;
|
||||
/** The prefetch queue */
|
||||
switch_queue_t *prefetch_queue;
|
||||
/** Max size of prefetch queue */
|
||||
int prefetch_queue_size;
|
||||
/** Size of prefetch thread pool */
|
||||
int prefetch_thread_count;
|
||||
/** Shutdown flag */
|
||||
int shutdown;
|
||||
/** Synchronizes shutdown of cache */
|
||||
switch_thread_rwlock_t *shutdown_lock;
|
||||
};
|
||||
static url_cache_t gcache;
|
||||
|
||||
@@ -778,6 +789,35 @@ static void setup_dir(url_cache_t *cache)
|
||||
}
|
||||
}
|
||||
|
||||
static int isUrl(const char *filename)
|
||||
{
|
||||
return !zstr(filename) && !strncmp("http://", filename, strlen("http://"));
|
||||
}
|
||||
|
||||
#define HTTP_PREFETCH_SYNTAX "<url>"
|
||||
SWITCH_STANDARD_API(http_cache_prefetch)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
char *url;
|
||||
|
||||
if (!isUrl(cmd)) {
|
||||
stream->write_function(stream, "USAGE: %s\n", HTTP_PREFETCH_SYNTAX);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* send to thread pool */
|
||||
url = strdup(cmd);
|
||||
if (switch_queue_trypush(gcache.prefetch_queue, url) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_safe_free(url);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Failed to queue prefetch request\n");
|
||||
stream->write_function(stream, "-ERR\n");
|
||||
} else {
|
||||
stream->write_function(stream, "+OK\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#define HTTP_GET_SYNTAX "<url>"
|
||||
/**
|
||||
* Get a file from the cache, download if it isn't cached
|
||||
@@ -789,7 +829,7 @@ SWITCH_STANDARD_API(http_cache_get)
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
char *filename;
|
||||
|
||||
if (zstr(cmd) || strncmp("http://", cmd, strlen("http://"))) {
|
||||
if (!isUrl(cmd)) {
|
||||
stream->write_function(stream, "USAGE: %s\n", HTTP_GET_SYNTAX);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -911,6 +951,44 @@ SWITCH_STANDARD_API(http_cache_clear)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thread to prefetch URLs
|
||||
* @param thread the thread
|
||||
* @param obj started flag
|
||||
* @return NULL
|
||||
*/
|
||||
static void *SWITCH_THREAD_FUNC prefetch_thread(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
int *started = obj;
|
||||
void *url = NULL;
|
||||
|
||||
switch_thread_rwlock_rdlock(gcache.shutdown_lock);
|
||||
*started = 1;
|
||||
|
||||
// process prefetch requests
|
||||
while (!gcache.shutdown) {
|
||||
if (switch_queue_pop(gcache.prefetch_queue, &url) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_api_execute("http_get", url, NULL, &stream);
|
||||
switch_safe_free(stream.data);
|
||||
switch_safe_free(url);
|
||||
}
|
||||
url = NULL;
|
||||
}
|
||||
|
||||
// shutting down- clear the queue
|
||||
while (switch_queue_trypop(gcache.prefetch_queue, &url) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_safe_free(url);
|
||||
url = NULL;
|
||||
}
|
||||
|
||||
switch_thread_rwlock_unlock(gcache.shutdown_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the module
|
||||
* @param cache to configure
|
||||
@@ -933,6 +1011,8 @@ static switch_status_t do_config(url_cache_t *cache)
|
||||
max_urls = 4000;
|
||||
default_max_age_sec = 86400;
|
||||
cache->location = SWITCH_PREFIX_DIR "/http_cache";
|
||||
cache->prefetch_queue_size = 100;
|
||||
cache->prefetch_thread_count = 8;
|
||||
|
||||
/* get params */
|
||||
settings = switch_xml_child(cfg, "settings");
|
||||
@@ -949,6 +1029,12 @@ static switch_status_t do_config(url_cache_t *cache)
|
||||
} else if (!strcasecmp(var, "default-max-age")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting default-max-age to %s\n", val);
|
||||
default_max_age_sec = atoi(val);
|
||||
} else if (!strcasecmp(var, "prefetch-queue-size")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting prefetch-queue-size to %s\n", val);
|
||||
cache->prefetch_queue_size = atoi(val);
|
||||
} else if (!strcasecmp(var, "prefetch-thread-count")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting prefetch-thread-count to %s\n", val);
|
||||
cache->prefetch_thread_count = atoi(val);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var);
|
||||
}
|
||||
@@ -971,6 +1057,16 @@ static switch_status_t do_config(url_cache_t *cache)
|
||||
status = SWITCH_STATUS_TERM;
|
||||
goto done;
|
||||
}
|
||||
if (cache->prefetch_queue_size <= 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "prefetch-queue-size must be > 0\n");
|
||||
status = SWITCH_STATUS_TERM;
|
||||
goto done;
|
||||
}
|
||||
if (cache->prefetch_thread_count <= 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "prefetch-thread-count must be > 0\n");
|
||||
status = SWITCH_STATUS_TERM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cache->max_url = max_urls;
|
||||
cache->default_max_age = (default_max_age_sec * 1000 * 1000); /* convert from seconds to nanoseconds */
|
||||
@@ -992,6 +1088,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load)
|
||||
SWITCH_ADD_API(api, "http_tryget", "HTTP GET from cache only", http_cache_tryget, HTTP_GET_SYNTAX);
|
||||
SWITCH_ADD_API(api, "http_put", "HTTP PUT", http_cache_put, HTTP_PUT_SYNTAX);
|
||||
SWITCH_ADD_API(api, "http_clear_cache", "Clear the cache", http_cache_clear, HTTP_CACHE_CLEAR_SYNTAX);
|
||||
SWITCH_ADD_API(api, "http_prefetch", "Prefetch document in a background thread. Use http_get to get the prefetched document", http_cache_prefetch, HTTP_PREFETCH_SYNTAX);
|
||||
|
||||
memset(&gcache, 0, sizeof(url_cache_t));
|
||||
gcache.pool = pool;
|
||||
@@ -1002,6 +1099,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load)
|
||||
|
||||
switch_core_hash_init(&gcache.map, gcache.pool);
|
||||
switch_mutex_init(&gcache.mutex, SWITCH_MUTEX_UNNESTED, gcache.pool);
|
||||
switch_thread_rwlock_create(&gcache.shutdown_lock, gcache.pool);
|
||||
|
||||
/* create the queue */
|
||||
gcache.queue.max_size = gcache.max_url;
|
||||
@@ -1011,6 +1109,21 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load)
|
||||
|
||||
setup_dir(&gcache);
|
||||
|
||||
/* Start the prefetch threads */
|
||||
switch_queue_create(&gcache.prefetch_queue, gcache.prefetch_queue_size, gcache.pool);
|
||||
for (int i = 0; i < gcache.prefetch_thread_count; i++) {
|
||||
int started = 0;
|
||||
switch_thread_t *thread;
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
switch_threadattr_create(&thd_attr, gcache.pool);
|
||||
switch_threadattr_detach_set(thd_attr, 1);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_thread_create(&thread, thd_attr, prefetch_thread, &started, gcache.pool);
|
||||
while (!started) {
|
||||
switch_sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -1020,6 +1133,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load)
|
||||
*/
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_http_cache_shutdown)
|
||||
{
|
||||
gcache.shutdown = 1;
|
||||
switch_queue_interrupt_all(gcache.prefetch_queue);
|
||||
switch_thread_rwlock_wrlock(gcache.shutdown_lock);
|
||||
|
||||
url_cache_clear(&gcache, NULL);
|
||||
switch_core_hash_destroy(&gcache.map);
|
||||
switch_mutex_destroy(gcache.mutex);
|
||||
|
||||
@@ -634,6 +634,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load)
|
||||
setenv("LADSPA_PATH", "/usr/lib64/ladspa/:/usr/local/lib/ladspa", 1);
|
||||
} else if (switch_directory_exists("/usr/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
|
||||
setenv("LADSPA_PATH", "/usr/lib/ladspa/:/usr/local/lib/ladspa", 1);
|
||||
} else if (switch_directory_exists("/usr/local/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
|
||||
setenv("LADSPA_PATH", "/usr/local/lib/ladspa", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1535,7 +1535,14 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt)
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "LCR Lookup on %s using profile %s\n", caller_profile->destination_number, caller_profile->context);
|
||||
routes.lookup_number = caller_profile->destination_number;
|
||||
routes.cid = (char *) caller_profile->caller_id_number;
|
||||
|
||||
if (caller_profile) {
|
||||
routes.cid = (char *) switch_channel_get_variable(channel, "effective_caller_id_number");
|
||||
if (!routes.cid) {
|
||||
routes.cid = (char *) caller_profile->caller_id_number;
|
||||
}
|
||||
}
|
||||
|
||||
if (lcr_do_lookup(&routes) == SWITCH_STATUS_SUCCESS) {
|
||||
if ((extension = switch_caller_extension_new(session, caller_profile->destination_number, caller_profile->destination_number)) == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "memory error!\n");
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Tamas Cseke <cstomi.levlist@gmail.com>
|
||||
*
|
||||
* mod_mongo.cpp -- API for MongoDB
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include "mod_mongo.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Tamas Cseke <cstomi.levlist@gmail.com>
|
||||
*
|
||||
* mod_mongo.h -- API for MongoDB
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MOD_MONGO_H
|
||||
#define MOD_MONGO_H
|
||||
|
||||
@@ -35,3 +66,13 @@ switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DB
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Tamas Cseke <cstomi.levlist@gmail.com>
|
||||
*
|
||||
* mongo_conn.cpp -- MongoDB connection pool
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
#include "mod_mongo.h"
|
||||
|
||||
@@ -169,3 +199,14 @@ switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DB
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
|
||||
@@ -397,6 +397,7 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
||||
switch_size_t retsize;
|
||||
switch_time_exp_t tm;
|
||||
const char *billrate;
|
||||
const char *billincrement;
|
||||
const char *billaccount;
|
||||
float nobal_amt = globals.nobal_amt;
|
||||
//float lowbal_amt = globals.lowbal_amt;
|
||||
@@ -416,6 +417,7 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
||||
|
||||
/* Variables kept in FS but relevant only to this module */
|
||||
billrate = switch_channel_get_variable(channel, "nibble_rate");
|
||||
billincrement = switch_channel_get_variable(channel, "nibble_increment");
|
||||
billaccount = switch_channel_get_variable(channel, "nibble_account");
|
||||
|
||||
if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) {
|
||||
@@ -493,8 +495,14 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
||||
(int) ((ts - nibble_data->lastts) / 1000000), date);
|
||||
|
||||
if ((ts - nibble_data->lastts) >= 0) {
|
||||
/* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */
|
||||
billamount = ((float) atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments;
|
||||
/* If billincrement is set we bill by it and not by time elapsed */
|
||||
if (!(switch_strlen_zero(billincrement))) {
|
||||
float chargedunits = ((int)((ts - nibble_data->lastts) / 1000000) <= (int)atof(billincrement)) ? ((float)atof(billincrement) * 1000000) : ceil((ts - nibble_data->lastts) / ((float)atof(billincrement) * 1000000)) * ((float)atof(billincrement) * 1000000);
|
||||
billamount = ((float) atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments;
|
||||
} else {
|
||||
/* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */
|
||||
billamount = ((float) atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Billing $%f to %s (Call: %s / %f so far)\n", billamount, billaccount,
|
||||
uuid, nibble_data->total);
|
||||
|
||||
@@ -63,10 +63,6 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
|
||||
@@ -446,7 +446,7 @@ switch_status_t load_configuration(switch_bool_t reload)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <descriptor> name\n");
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s\n", name);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding tone_descriptor: %s\n", name);
|
||||
if (tone_descriptor_create(&descriptor, name, spandsp_globals.config_pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to allocate tone_descriptor: %s\n", name);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
@@ -467,7 +467,7 @@ switch_status_t load_configuration(switch_bool_t reload)
|
||||
"Unable to add tone_descriptor: %s, tone: %s. (too many tones)\n", name, tone_name);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);
|
||||
/* add elements to tone */
|
||||
for (element = switch_xml_child(tone, "element"); element; element = switch_xml_next(element)) {
|
||||
@@ -502,7 +502,7 @@ switch_status_t load_configuration(switch_bool_t reload)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid element param.\n");
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"Adding tone_descriptor: %s, tone: %s(%d), element (%d, %d, %d, %d)\n", name, tone_name, id, freq1, freq2, min, max);
|
||||
tone_descriptor_add_tone_element(descriptor, id, freq1, freq2, min, max);
|
||||
}
|
||||
|
||||
@@ -1303,7 +1303,7 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
|
||||
prefix = spandsp_globals.prepend_string;
|
||||
}
|
||||
|
||||
if (!(pvt->filename = switch_core_session_sprintf(session, "%s/%s-%ld-%ld.tif", spandsp_globals.spool, prefix, spandsp_globals.total_sessions, time))) {
|
||||
if (!(pvt->filename = switch_core_session_sprintf(session, "%s/%s-%ld-%" SWITCH_TIME_T_FMT ".tif", spandsp_globals.spool, prefix, spandsp_globals.total_sessions, time))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot automatically set fax RX destination file\n");
|
||||
goto done;
|
||||
}
|
||||
@@ -1683,7 +1683,7 @@ static switch_status_t t38_gateway_on_consume_media(switch_core_session_t *sessi
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
int16_t *buf = NULL;
|
||||
switch_status_t status;
|
||||
switch_size_t tx;
|
||||
int tx;
|
||||
const char *t38_trace = switch_channel_get_variable(channel, "t38_trace");
|
||||
char *trace_read, *trace_write;
|
||||
zap_socket_t read_fd = FAX_INVALID_SOCKET, write_fd = FAX_INVALID_SOCKET;
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
#ifdef __APPLE__
|
||||
#include <util.h>
|
||||
#include <sys/ioctl.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <libutil.h>
|
||||
#include <termios.h>
|
||||
#else
|
||||
#include <pty.h>
|
||||
#endif
|
||||
@@ -57,8 +60,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#ifndef WIN32
|
||||
#ifdef __UCLIBC__
|
||||
#else
|
||||
#if defined(HAVE_BYTESWAP_H)
|
||||
#include <byteswap.h>
|
||||
#elif defined(USE_SYS_ENDIAN_H)
|
||||
@@ -68,6 +69,7 @@
|
||||
#define bswap_16 OSSwapInt16
|
||||
#define bswap_32 OSSwapInt32
|
||||
#define bswap_64 OSSwapInt64
|
||||
#elif defined (__UCLIBC__)
|
||||
#else
|
||||
#define bswap_16(value) \
|
||||
((((value) & 0xff) << 8) | ((value) >> 8))
|
||||
@@ -84,7 +86,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/signal.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef WIN32
|
||||
|
||||
@@ -428,6 +428,9 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
char *dest;
|
||||
int in = -1;
|
||||
|
||||
const char *timeout, *orbit_exten, *orbit_dialplan, *orbit_context;
|
||||
char *timeout_str = "", *orbit_exten_str = "", *orbit_dialplan_str = "", *orbit_context_str = "";
|
||||
|
||||
lot = valet_find_lot(lot_name, SWITCH_TRUE);
|
||||
switch_assert(lot);
|
||||
|
||||
@@ -586,7 +589,28 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
music = "silence_stream://-1";
|
||||
}
|
||||
|
||||
dest = switch_core_session_sprintf(session, "set:valet_ticket=%s,set:valet_hold_music=%s,sleep:1000,valet_park:%s %s",
|
||||
if ((orbit_exten = switch_channel_get_variable(channel, "valet_parking_orbit_exten"))) {
|
||||
orbit_exten_str = switch_core_session_sprintf(session, "set:valet_parking_orbit_exten=%s,", orbit_exten);
|
||||
}
|
||||
|
||||
if ((orbit_dialplan = switch_channel_get_variable(channel, "valet_parking_orbit_dialplan"))) {
|
||||
orbit_dialplan_str = switch_core_session_sprintf(session, "set:valet_parking_orbit_dialplan=%s,", orbit_dialplan);
|
||||
}
|
||||
|
||||
if ((orbit_context = switch_channel_get_variable(channel, "valet_parking_orbit_context"))) {
|
||||
orbit_context_str = switch_core_session_sprintf(session, "set:valet_parking_orbit_context=%s,", orbit_context);
|
||||
}
|
||||
|
||||
if ((timeout = switch_channel_get_variable(channel, "valet_parking_timeout"))) {
|
||||
timeout_str = switch_core_session_sprintf(session, "set:valet_parking_timeout=%s,", timeout);
|
||||
}
|
||||
|
||||
dest = switch_core_session_sprintf(session, "%s%s%s%s"
|
||||
"set:valet_ticket=%s,set:valet_hold_music=%s,sleep:1000,valet_park:%s %s",
|
||||
timeout_str,
|
||||
orbit_exten_str,
|
||||
orbit_dialplan_str,
|
||||
orbit_context_str,
|
||||
token->uuid, music, lot_name, ext);
|
||||
switch_channel_set_variable(channel, "inline_destination", dest);
|
||||
|
||||
|
||||
@@ -989,6 +989,8 @@ typedef enum {
|
||||
#define VM_ENTER_ID_MACRO "voicemail_enter_id"
|
||||
#define VM_ENTER_PASS_MACRO "voicemail_enter_pass"
|
||||
#define VM_FAIL_AUTH_MACRO "voicemail_fail_auth"
|
||||
#define VM_CHANGE_PASS_SUCCESS_MACRO "voicemail_change_pass_success"
|
||||
#define VM_CHANGE_PASS_FAIL_MACRO "voicemail_change_pass_fail"
|
||||
#define VM_ABORT_MACRO "voicemail_abort"
|
||||
#define VM_HELLO_MACRO "voicemail_hello"
|
||||
#define VM_GOODBYE_MACRO "voicemail_goodbye"
|
||||
@@ -2164,28 +2166,52 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
char macro[256] = "";
|
||||
switch_event_t *params;
|
||||
switch_xml_t xx_user, xx_domain, xx_domain_root;
|
||||
int fail = 0;
|
||||
int ok = 0;
|
||||
|
||||
switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", VM_ENTER_PASS_MACRO, profile->terminator_key);
|
||||
TRY_CODE(switch_ivr_read(session, 0, 255, macro, NULL, buf, sizeof(buf), 10000, profile->terminator_key, 0));
|
||||
sql = switch_mprintf("update voicemail_prefs set password='%s' where username='%s' and domain='%s'", buf, myid, domain_name);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(file_path);
|
||||
switch_safe_free(sql);
|
||||
while (!ok) {
|
||||
fail = 0;
|
||||
switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", VM_ENTER_PASS_MACRO, profile->terminator_key);
|
||||
TRY_CODE(switch_ivr_read(session, 0, 255, macro, NULL, buf, sizeof(buf), 10000, profile->terminator_key, 0));
|
||||
|
||||
|
||||
switch_event_create_subclass(¶ms, SWITCH_EVENT_CUSTOM, VM_EVENT_MAINT);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-Action", "change-password");
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-User-Password", buf);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-User", myid);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-Domain", domain_name);
|
||||
switch_channel_event_set_data(channel, params);
|
||||
|
||||
if (switch_xml_locate_user("id", myid, domain_name, switch_channel_get_variable(channel, "network_addr"),
|
||||
&xx_domain_root, &xx_domain, &xx_user, NULL, params) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_xml_free(xx_domain_root);
|
||||
switch_event_create_subclass(¶ms, SWITCH_EVENT_CUSTOM, VM_EVENT_MAINT);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-Action", "change-password");
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-User-Password", buf);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-User", myid);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-Domain", domain_name);
|
||||
switch_channel_event_set_data(channel, params);
|
||||
|
||||
if (switch_xml_locate_user("id", myid, domain_name, switch_channel_get_variable(channel, "network_addr"),
|
||||
&xx_domain_root, &xx_domain, &xx_user, NULL, params) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_xml_t x_result;
|
||||
|
||||
if ((x_result = switch_xml_child(xx_user, "result"))) {
|
||||
if (!switch_true(switch_xml_attr_soft(x_result, "success"))) {
|
||||
fail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
switch_xml_free(xx_domain_root);
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
/* add feedback for user - let him/her know that the password they tried to change to is not allowed */
|
||||
/* change the following macro to VM_CHANGE_PASS_FAIL_MACRO when new prompts have been recorded */
|
||||
switch_ivr_phrase_macro(session, VM_FAIL_AUTH_MACRO, NULL, NULL, NULL);
|
||||
} else {
|
||||
sql = switch_mprintf("update voicemail_prefs set password='%s' where username='%s' and domain='%s'", buf, myid, domain_name);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(file_path);
|
||||
switch_safe_free(sql);
|
||||
ok = 1;
|
||||
/* add feedback for user - let him/her know that password change was successful */
|
||||
switch_ivr_phrase_macro(session, VM_CHANGE_PASS_SUCCESS_MACRO, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
switch_event_destroy(¶ms);
|
||||
}
|
||||
|
||||
switch_event_fire(¶ms);
|
||||
|
||||
} else if (!strcmp(input, profile->record_name_key)) {
|
||||
switch_event_t *params;
|
||||
file_path = switch_mprintf("%s%srecorded_name.%s", dir_path, SWITCH_PATH_SEPARATOR, profile->file_ext);
|
||||
@@ -2498,19 +2524,21 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
status = switch_ivr_phrase_macro(session, VM_GOODBYE_MACRO, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (x_user) {
|
||||
switch_xml_free(x_user);
|
||||
x_user = NULL;
|
||||
}
|
||||
|
||||
if (auth_only) {
|
||||
if (authed) {
|
||||
switch_channel_set_variable(channel, "user_pin_authenticated", "true");
|
||||
switch_channel_set_variable(channel, "user_pin_authenticated_user", myid);
|
||||
if (!zstr(myid)) switch_ivr_set_user(session, myid);
|
||||
} else {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_USER_CHALLENGE);
|
||||
}
|
||||
}
|
||||
|
||||
if (x_user) {
|
||||
switch_xml_free(x_user);
|
||||
x_user = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3403,7 +3431,7 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
|
||||
status = create_file(session, profile, record_macro, file_path, &message_len, SWITCH_TRUE, key_buf, buf);
|
||||
|
||||
if ((status == SWITCH_STATUS_NOTFOUND)) {
|
||||
if (status == SWITCH_STATUS_NOTFOUND) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -3431,7 +3459,20 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
switch_core_session_get_pool(session), caller_id_name, caller_id_number, NULL, SWITCH_FALSE,
|
||||
session ? switch_core_session_get_uuid(session) : NULL, session);
|
||||
switch_event_destroy(&vars);
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
switch_core_time_duration_t duration;
|
||||
char duration_str[80];
|
||||
switch_time_t l_duration = switch_time_make(message_len, 0);
|
||||
|
||||
switch_core_measure_time(l_duration, &duration);
|
||||
duration.day += duration.yr * 365;
|
||||
duration.hr += duration.day * 24;
|
||||
|
||||
switch_snprintf(duration_str, sizeof(duration_str), "%.2u:%.2u:%.2u", duration.hr, duration.min, duration.sec);
|
||||
|
||||
switch_channel_set_variable(channel, "voicemail_message_len", duration_str);
|
||||
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to deliver message\n");
|
||||
TRY_CODE(switch_ivr_phrase_macro(session, VM_ACK_MACRO, "deleted", NULL, NULL));
|
||||
}
|
||||
@@ -4461,9 +4502,9 @@ SWITCH_STANDARD_API(voicemail_read_api_function)
|
||||
|
||||
if (mread) {
|
||||
if (uuid) {
|
||||
sql = switch_mprintf("update voicemail_msgs set read_epoch=%ld,flags='save' where uuid='%q'", (long) switch_epoch_time_now(NULL), uuid);
|
||||
sql = switch_mprintf("update voicemail_msgs set read_epoch=%ld where uuid='%q'", (long) switch_epoch_time_now(NULL), uuid);
|
||||
} else {
|
||||
sql = switch_mprintf("update voicemail_msgs set read_epoch=%ld,flags='save' where domain='%q'", (long) switch_epoch_time_now(NULL), domain);
|
||||
sql = switch_mprintf("update voicemail_msgs set read_epoch=%ld where domain='%q'", (long) switch_epoch_time_now(NULL), domain);
|
||||
}
|
||||
} else{
|
||||
if (uuid) {
|
||||
@@ -5586,6 +5627,158 @@ done:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_EMAIL_USAGE "<profile> <domain> <user> <uuid> <email>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_email_function)
|
||||
{
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL, *uuid = NULL, *email = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
char *argv[7] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
msg_get_callback_t cbt = { 0 };
|
||||
char *sql;
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
uuid = argv[3];
|
||||
if (argv[4])
|
||||
email = argv[4];
|
||||
|
||||
if (!profile_name || !domain || !id || !uuid || !email) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
} else {
|
||||
char *from;
|
||||
char *headers, *header_string;
|
||||
char *body;
|
||||
int priority = 3;
|
||||
switch_size_t retsize;
|
||||
switch_time_exp_t tm;
|
||||
char date[80] = "";
|
||||
int total_new_messages = 0;
|
||||
int total_saved_messages = 0;
|
||||
int total_new_urgent_messages = 0;
|
||||
int total_saved_urgent_messages = 0;
|
||||
int32_t message_len = 0;
|
||||
char *p;
|
||||
switch_time_t l_duration = 0;
|
||||
switch_core_time_duration_t duration;
|
||||
char duration_str[80];
|
||||
char *formatted_cid_num = NULL;
|
||||
|
||||
sql = switch_mprintf("SELECT * FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND uuid = '%q' ORDER BY read_flags, created_epoch", id, domain, uuid);
|
||||
memset(&cbt, 0, sizeof(cbt));
|
||||
switch_event_create(&cbt.my_params, SWITCH_EVENT_GENERAL);
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, message_get_callback, &cbt);
|
||||
switch_safe_free(sql);
|
||||
|
||||
if (!strcasecmp(switch_event_get_header(cbt.my_params, "VM-Message-Read-Flags"), URGENT_FLAG_STRING)) {
|
||||
priority = 1;
|
||||
}
|
||||
|
||||
message_count(profile, id, domain, switch_event_get_header(cbt.my_params, "VM-Message-Folder"), &total_new_messages, &total_saved_messages,
|
||||
&total_new_urgent_messages, &total_saved_urgent_messages);
|
||||
|
||||
switch_time_exp_lt(&tm, switch_time_make(atol(switch_event_get_header(cbt.my_params, "VM-Message-Received-Epoch")), 0));
|
||||
switch_strftime(date, &retsize, sizeof(date), profile->date_fmt, &tm);
|
||||
|
||||
formatted_cid_num = switch_format_number(switch_event_get_header(cbt.my_params, "VM-Message-Caller-Number"));
|
||||
|
||||
/* Legacy Mod_VoiceMail variable */
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "Message-Type", "forwarded-voicemail");
|
||||
switch_event_add_header(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_total_new_messages", "%d", total_new_messages);
|
||||
switch_event_add_header(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_total_saved_messages", "%d", total_saved_messages);
|
||||
switch_event_add_header(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_urgent_new_messages", "%d", total_new_urgent_messages);
|
||||
switch_event_add_header(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_urgent_saved_messages", "%d", total_saved_urgent_messages);
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_current_folder", switch_event_get_header(cbt.my_params, "VM-Message-Folder"));
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_account", id);
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_domain", domain);
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_caller_id_number", switch_event_get_header(cbt.my_params, "VM-Message-Caller-Number"));
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_formatted_caller_id_number", formatted_cid_num);
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_caller_id_name", switch_event_get_header(cbt.my_params, "VM-Message-Caller-Name"));
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_file_path", switch_event_get_header(cbt.my_params, "VM-Message-File-Path"));
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_read_flags", switch_event_get_header(cbt.my_params, "VM-Message-Read-Flags"));
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_time", date);
|
||||
switch_event_add_header(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_priority", "%d", priority);
|
||||
|
||||
|
||||
message_len = atoi(switch_event_get_header(cbt.my_params, "VM-Message-Duration"));
|
||||
switch_safe_free(formatted_cid_num);
|
||||
|
||||
l_duration = switch_time_make(atol(switch_event_get_header(cbt.my_params, "VM-Message-Duration")), 0);
|
||||
switch_core_measure_time(l_duration, &duration);
|
||||
duration.day += duration.yr * 365;
|
||||
duration.hr += duration.day * 24;
|
||||
|
||||
switch_snprintf(duration_str, sizeof(duration_str), "%.2u:%.2u:%.2u", duration.hr, duration.min, duration.sec);
|
||||
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_message_len", duration_str);
|
||||
switch_event_add_header_string(cbt.my_params, SWITCH_STACK_BOTTOM, "voicemail_email", email);
|
||||
|
||||
if (zstr(profile->email_from)) {
|
||||
from = switch_core_sprintf(pool, "%s@%s", id, domain);
|
||||
} else {
|
||||
from = switch_event_expand_headers(cbt.my_params, profile->email_from);;
|
||||
}
|
||||
|
||||
if (zstr(profile->email_headers)) {
|
||||
headers = switch_core_sprintf(pool,
|
||||
"From: FreeSWITCH mod_voicemail <%s@%s>\nSubject: Voicemail from %s %s\nX-Priority: %d",
|
||||
id, domain, switch_event_get_header(cbt.my_params, "VM-Message-Caller-Name"),
|
||||
switch_event_get_header(cbt.my_params, "VM-Message-Caller-Number"), priority);
|
||||
} else {
|
||||
headers = switch_event_expand_headers(cbt.my_params, profile->email_headers);
|
||||
}
|
||||
|
||||
p = headers + (strlen(headers) - 1);
|
||||
if (*p == '\n') {
|
||||
if (*(p - 1) == '\r') {
|
||||
p--;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
header_string = switch_core_sprintf(pool, "%s\nX-Voicemail-Length: %u", headers, message_len);
|
||||
|
||||
if (profile->email_body) {
|
||||
body = switch_event_expand_headers(cbt.my_params, profile->email_body);
|
||||
} else {
|
||||
body = switch_mprintf("%u second Voicemail from %s %s", message_len, switch_event_get_header(cbt.my_params, "VM-Message-Caller-Name"), switch_event_get_header(cbt.my_params, "VM-Message-Caller-Number"));
|
||||
}
|
||||
|
||||
switch_simple_email(email, from, header_string, body, switch_event_get_header(cbt.my_params, "VM-Message-File-Path"), profile->convert_cmd, profile->convert_ext);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending message to %s\n", email);
|
||||
switch_safe_free(body);
|
||||
|
||||
switch_event_fire(&cbt.my_params);
|
||||
|
||||
|
||||
profile_rwunlock(profile);
|
||||
}
|
||||
stream->write_function(stream, "-OK\n");
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_COUNT_USAGE "<format> <profile> <domain> <user> <folder>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_count_function)
|
||||
{
|
||||
@@ -5712,6 +5905,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_get", "vm_fsdb_msg_get", vm_fsdb_msg_get_function, VM_FSDB_MSG_GET_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_delete", "vm_fsdb_msg_delete", vm_fsdb_msg_delete_function, VM_FSDB_MSG_DELETE_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_undelete", "vm_fsdb_msg_undelete", vm_fsdb_msg_undelete_function, VM_FSDB_MSG_UNDELETE_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_email", "vm_fsdb_msg_email", vm_fsdb_msg_email_function, VM_FSDB_MSG_EMAIL_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_purge", "vm_fsdb_msg_purge", vm_fsdb_msg_purge_function, VM_FSDB_MSG_PURGE_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_save", "vm_fsdb_msg_save", vm_fsdb_msg_save_function, VM_FSDB_MSG_SAVE_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_forward", "vm_fsdb_msg_forward", vm_fsdb_msg_forward_function, VM_FSDB_MSG_FORWARD_USAGE);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
BASE=../../../..
|
||||
LOCAL_OBJS=ivr.o utils.o config.o menu.o
|
||||
include $(BASE)/build/modmake.rules
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* config.c -- VoiceMail IVR Config
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
const char *global_cf = "voicemail_ivr.conf";
|
||||
|
||||
static void append_event_profile(vmivr_menu_t *menu);
|
||||
static void populate_dtmfa_from_event(vmivr_menu_t *menu);
|
||||
|
||||
void menu_init(vmivr_profile_t *profile, vmivr_menu_t *menu) {
|
||||
switch_xml_t cfg, xml, x_profiles, x_profile, x_keys, x_phrases, x_menus, x_menu, x_settings;
|
||||
|
||||
menu->profile = profile;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||
goto end;
|
||||
}
|
||||
if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No profiles group\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (profile->event_settings) {
|
||||
/* TODO Replace this with a switch_event_merge_not_set(...) */
|
||||
switch_event_t *menu_default;
|
||||
switch_event_create(&menu_default, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
if (menu->event_settings) {
|
||||
switch_event_merge(menu_default, menu->event_settings);
|
||||
switch_event_destroy(&menu->event_settings);
|
||||
}
|
||||
|
||||
switch_event_create(&menu->event_settings, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
switch_event_merge(menu->event_settings, profile->event_settings);
|
||||
switch_event_merge(menu->event_settings, menu_default);
|
||||
switch_event_destroy(&menu_default);
|
||||
}
|
||||
|
||||
{
|
||||
const char *s_max_attempts = switch_event_get_header(menu->event_settings, "IVR-Maximum-Attempts");
|
||||
const char *s_entry_timeout = switch_event_get_header(menu->event_settings, "IVR-Entry-Timeout");
|
||||
menu->ivr_maximum_attempts = atoi(s_max_attempts);
|
||||
menu->ivr_entry_timeout = atoi(s_entry_timeout);
|
||||
}
|
||||
|
||||
if ((x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile->name))) {
|
||||
if ((x_menus = switch_xml_child(x_profile, "menus"))) {
|
||||
if ((x_menu = switch_xml_find_child(x_menus, "menu", "name", menu->name))) {
|
||||
|
||||
if ((x_keys = switch_xml_child(x_menu, "keys"))) {
|
||||
switch_event_import_xml(switch_xml_child(x_keys, "key"), "dtmf", "action", &menu->event_keys_dtmf);
|
||||
switch_event_import_xml(switch_xml_child(x_keys, "key"), "action", "dtmf", &menu->event_keys_action);
|
||||
switch_event_import_xml(switch_xml_child(x_keys, "key"), "action", "variable", &menu->event_keys_varname);
|
||||
}
|
||||
if ((x_phrases = switch_xml_child(x_menu, "phrases"))) {
|
||||
switch_event_import_xml(switch_xml_child(x_phrases, "phrase"), "name", "value", &menu->event_phrases);
|
||||
}
|
||||
if ((x_settings = switch_xml_child(x_profile, "settings"))) {
|
||||
switch_event_import_xml(switch_xml_child(x_settings, "param"), "name", "value", &menu->event_settings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
if (xml)
|
||||
switch_xml_free(xml);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void menu_instance_init(vmivr_menu_t *menu) {
|
||||
append_event_profile(menu);
|
||||
|
||||
populate_dtmfa_from_event(menu);
|
||||
}
|
||||
|
||||
void menu_instance_free(vmivr_menu_t *menu) {
|
||||
if (menu->phrase_params) {
|
||||
switch_event_destroy(&menu->phrase_params);
|
||||
}
|
||||
memset(&menu->ivre_d, 0, sizeof(menu->ivre_d));
|
||||
}
|
||||
|
||||
void menu_free(vmivr_menu_t *menu) {
|
||||
if (menu->event_keys_dtmf) {
|
||||
switch_event_destroy(&menu->event_keys_dtmf);
|
||||
}
|
||||
if (menu->event_keys_action) {
|
||||
switch_event_destroy(&menu->event_keys_action);
|
||||
}
|
||||
if (menu->event_keys_varname) {
|
||||
switch_event_destroy(&menu->event_keys_varname);
|
||||
}
|
||||
|
||||
if (menu->event_phrases) {
|
||||
switch_event_destroy(&menu->event_phrases);
|
||||
}
|
||||
if (menu->event_settings) {
|
||||
switch_event_destroy(&menu->event_settings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void append_event_profile(vmivr_menu_t *menu) {
|
||||
|
||||
if (!menu->phrase_params) {
|
||||
switch_event_create(&menu->phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
}
|
||||
|
||||
/* Used for some appending function */
|
||||
if (menu->profile && menu->profile->name && menu->profile->id && menu->profile->domain) {
|
||||
switch_event_add_header(menu->phrase_params, SWITCH_STACK_BOTTOM, "VM-Profile", "%s", menu->profile->name);
|
||||
switch_event_add_header(menu->phrase_params, SWITCH_STACK_BOTTOM, "VM-Account-ID", "%s", menu->profile->id);
|
||||
switch_event_add_header(menu->phrase_params, SWITCH_STACK_BOTTOM, "VM-Account-Domain", "%s", menu->profile->domain);
|
||||
}
|
||||
}
|
||||
|
||||
static void populate_dtmfa_from_event(vmivr_menu_t *menu) {
|
||||
int i = 0;
|
||||
if (menu->event_keys_dtmf) {
|
||||
switch_event_header_t *hp;
|
||||
|
||||
for (hp = menu->event_keys_dtmf->headers; hp; hp = hp->next) {
|
||||
if (strlen(hp->name) < 3 && hp->value) { /* TODO This is a hack to discard default FS Events ! */
|
||||
const char *varphrasename = switch_event_get_header(menu->event_keys_varname, hp->value);
|
||||
menu->dtmfa[i++] = hp->name;
|
||||
|
||||
if (varphrasename && !zstr(varphrasename)) {
|
||||
switch_event_add_header(menu->phrase_params, SWITCH_STACK_BOTTOM, varphrasename, "%s", hp->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
menu->dtmfa[i++] = '\0';
|
||||
}
|
||||
|
||||
vmivr_profile_t *get_profile(switch_core_session_t *session, const char *profile_name)
|
||||
{
|
||||
vmivr_profile_t *profile = NULL;
|
||||
switch_xml_t cfg, xml, x_profiles, x_profile, x_apis, x_settings, param;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||
return profile;
|
||||
}
|
||||
if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile_name))) {
|
||||
if (!(profile = switch_core_session_alloc(session, sizeof(vmivr_profile_t)))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Alloc Failure\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
profile->name = profile_name;
|
||||
|
||||
profile->current_msg = 0;
|
||||
profile->current_msg_uuid = NULL;
|
||||
|
||||
profile->folder_name = VM_FOLDER_ROOT;
|
||||
profile->folder_filter = VM_MSG_NOT_READ;
|
||||
|
||||
/* TODO Make the following configurable */
|
||||
profile->api_profile = profile->name;
|
||||
profile->menu_check_auth = "std_authenticate";
|
||||
profile->menu_check_main = "std_main_menu";
|
||||
profile->menu_check_terminate = "std_purge";
|
||||
|
||||
/* Populate default general settings */
|
||||
switch_event_create(&profile->event_settings, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "IVR-Maximum-Attempts", "%d", 3);
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "IVR-Entry-Timeout", "%d", 3000);
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "Exit-Purge", "%s", "true");
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "Password-Mask", "%s", "XXX.");
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "User-Mask", "%s", "X.");
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "Record-Format", "%s", "wav");
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "Record-Silence-Hits", "%d", 4);
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "Record-Silence-Threshold", "%d", 200);
|
||||
switch_event_add_header(profile->event_settings, SWITCH_STACK_BOTTOM, "Record-Maximum-Length", "%d", 30);
|
||||
|
||||
if ((x_settings = switch_xml_child(x_profile, "settings"))) {
|
||||
switch_event_import_xml(switch_xml_child(x_settings, "param"), "name", "value", &profile->event_settings);
|
||||
}
|
||||
|
||||
if ((x_apis = switch_xml_child(x_profile, "apis"))) {
|
||||
int total_options = 0;
|
||||
int total_invalid_options = 0;
|
||||
for (param = switch_xml_child(x_apis, "api"); param; param = param->next) {
|
||||
char *var, *val;
|
||||
if ((var = (char *) switch_xml_attr_soft(param, "name")) && (val = (char *) switch_xml_attr_soft(param, "value"))) {
|
||||
if (!strcasecmp(var, "msg_undelete") && !profile->api_msg_undelete)
|
||||
profile->api_msg_undelete = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_delete") && !profile->api_msg_delete)
|
||||
profile->api_msg_delete = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_list") && !profile->api_msg_list)
|
||||
profile->api_msg_list = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_count") && !profile->api_msg_count)
|
||||
profile->api_msg_count = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_save") && !profile->api_msg_save)
|
||||
profile->api_msg_save = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_purge") && !profile->api_msg_purge)
|
||||
profile->api_msg_purge = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_get") && !profile->api_msg_get)
|
||||
profile->api_msg_get = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_forward") && !profile->api_msg_forward)
|
||||
profile->api_msg_forward = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "pref_greeting_set") && !profile->api_pref_greeting_set)
|
||||
profile->api_pref_greeting_set = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "pref_recname_set") && !profile->api_pref_recname_set)
|
||||
profile->api_pref_recname_set = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "pref_password_set") && !profile->api_pref_password_set)
|
||||
profile->api_pref_password_set = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "auth_login") && !profile->api_auth_login)
|
||||
profile->api_auth_login = switch_core_session_strdup(session, val);
|
||||
else
|
||||
total_invalid_options++;
|
||||
total_options++;
|
||||
}
|
||||
}
|
||||
if (total_options - total_invalid_options != 12) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing api definition for profile '%s'\n", profile_name);
|
||||
profile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
switch_xml_free(xml);
|
||||
return profile;
|
||||
}
|
||||
|
||||
void free_profile(vmivr_profile_t *profile) {
|
||||
if (profile->event_settings) {
|
||||
switch_event_destroy(&profile->event_settings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* config.c -- VoiceMail IVR Config
|
||||
*
|
||||
*/
|
||||
#include "ivr.h"
|
||||
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
extern const char *global_cf;
|
||||
|
||||
#define VM_FOLDER_ROOT "inbox";
|
||||
#define VM_MSG_NOT_READ "not-read"
|
||||
#define VM_MSG_SAVED "save"
|
||||
#define VM_MSG_NEW "new"
|
||||
|
||||
struct vmivr_profile {
|
||||
const char *name;
|
||||
|
||||
const char *domain;
|
||||
const char *id;
|
||||
|
||||
int current_msg;
|
||||
const char *current_msg_uuid;
|
||||
|
||||
const char *folder_name;
|
||||
const char *folder_filter;
|
||||
|
||||
const char *menu_check_auth;
|
||||
const char *menu_check_main;
|
||||
const char *menu_check_terminate;
|
||||
|
||||
switch_bool_t authorized;
|
||||
|
||||
const char *api_profile;
|
||||
const char *api_auth_login;
|
||||
const char *api_msg_delete;
|
||||
const char *api_msg_undelete;
|
||||
const char *api_msg_list;
|
||||
const char *api_msg_count;
|
||||
const char *api_msg_save;
|
||||
const char *api_msg_purge;
|
||||
const char *api_msg_get;
|
||||
const char *api_msg_forward;
|
||||
const char *api_pref_greeting_set;
|
||||
const char *api_pref_recname_set;
|
||||
const char *api_pref_password_set;
|
||||
|
||||
switch_event_t *event_settings;
|
||||
};
|
||||
typedef struct vmivr_profile vmivr_profile_t;
|
||||
|
||||
struct vmivr_menu {
|
||||
const char *name;
|
||||
vmivr_profile_t *profile;
|
||||
|
||||
switch_event_t *event_keys_action;
|
||||
switch_event_t *event_keys_dtmf;
|
||||
switch_event_t *event_keys_varname;
|
||||
switch_event_t *event_settings;
|
||||
switch_event_t *event_phrases;
|
||||
|
||||
char *dtmfa[16];
|
||||
switch_event_t *phrase_params;
|
||||
ivre_data_t ivre_d;
|
||||
|
||||
int ivr_maximum_attempts;
|
||||
int ivr_entry_timeout;
|
||||
};
|
||||
typedef struct vmivr_menu vmivr_menu_t;
|
||||
|
||||
vmivr_profile_t *get_profile(switch_core_session_t *session, const char *profile_name);
|
||||
void free_profile(vmivr_profile_t *profile);
|
||||
|
||||
void menu_init(vmivr_profile_t *profile, vmivr_menu_t *menu);
|
||||
void menu_instance_init(vmivr_menu_t *menu);
|
||||
void menu_instance_free(vmivr_menu_t *menu);
|
||||
void menu_free(vmivr_menu_t *menu);
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* ivr.c -- VoiceMail IVR Engone
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#include "ivr.h"
|
||||
|
||||
static int match_dtmf(switch_core_session_t *session, ivre_data_t *loc) {
|
||||
switch_bool_t is_invalid[128] = { SWITCH_FALSE };
|
||||
int i;
|
||||
loc->potentialMatch = NULL;
|
||||
loc->completeMatch = NULL;
|
||||
loc->potentialMatchCount = 0;
|
||||
|
||||
for (i = 0; i < loc->dtmf_received; i++) {
|
||||
int j;
|
||||
loc->potentialMatchCount = 0;
|
||||
for (j = 0; !zstr(loc->dtmf_accepted[j]) && j < 128; j++) {
|
||||
switch_bool_t cMatch = SWITCH_FALSE;
|
||||
char test[2] = { 0 };
|
||||
|
||||
if (is_invalid[j])
|
||||
continue;
|
||||
|
||||
test[0] = loc->dtmf_stored[i];
|
||||
if (loc->dtmf_accepted[j][i] == 'N' && atoi(test) >= 2 && atoi(test) <= 9)
|
||||
cMatch = SWITCH_TRUE;
|
||||
if (loc->dtmf_accepted[j][i] == 'X' && atoi(test) >= 0 && atoi(test) <= 9) {
|
||||
cMatch = SWITCH_TRUE;
|
||||
}
|
||||
if (i >= strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.')
|
||||
cMatch = SWITCH_TRUE;
|
||||
if (loc->dtmf_accepted[j][i] == loc->dtmf_stored[i])
|
||||
cMatch = SWITCH_TRUE;
|
||||
|
||||
if (cMatch == SWITCH_FALSE) {
|
||||
is_invalid[j] = SWITCH_TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.') {
|
||||
loc->completeMatch = loc->dtmf_accepted[j];
|
||||
}
|
||||
if (i == loc->dtmf_received - 1 && loc->dtmf_received == strlen(loc->dtmf_accepted[j]) && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] != '.') {
|
||||
loc->completeMatch = loc->dtmf_accepted[j];
|
||||
continue;
|
||||
}
|
||||
loc->potentialMatchCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static switch_status_t cb_on_dtmf_ignore(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
|
||||
{
|
||||
switch (itype) {
|
||||
case SWITCH_INPUT_TYPE_DTMF:
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
|
||||
switch_channel_queue_dtmf(channel, dtmf);
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t cb_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
|
||||
{
|
||||
ivre_data_t *loc = (ivre_data_t*) buf;
|
||||
|
||||
switch (itype) {
|
||||
case SWITCH_INPUT_TYPE_DTMF:
|
||||
{
|
||||
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
|
||||
switch_bool_t audio_was_stopped = loc->audio_stopped;
|
||||
loc->audio_stopped = SWITCH_TRUE;
|
||||
|
||||
if (loc->dtmf_received >= sizeof(loc->dtmf_stored)) {
|
||||
loc->result = RES_BUFFER_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
if (!loc->terminate_key || dtmf->digit != loc->terminate_key)
|
||||
loc->dtmf_stored[loc->dtmf_received++] = dtmf->digit;
|
||||
|
||||
match_dtmf(session, loc);
|
||||
|
||||
if (loc->terminate_key && dtmf->digit == loc->terminate_key && loc->result == RES_WAITFORMORE) {
|
||||
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
|
||||
loc->result = RES_FOUND;
|
||||
} else {
|
||||
loc->result = RES_INVALID;
|
||||
}
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else {
|
||||
if (loc->potentialMatchCount == 0 && loc->completeMatch != NULL) {
|
||||
loc->result = RES_FOUND;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else if (loc->potentialMatchCount > 0) {
|
||||
loc->result = RES_WAITFORMORE;
|
||||
if (!audio_was_stopped)
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else {
|
||||
loc->result = RES_INVALID;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t ivre_init(ivre_data_t *loc, char **dtmf_accepted) {
|
||||
int i;
|
||||
|
||||
memset(loc, 0, sizeof(*loc));
|
||||
|
||||
for (i = 0; dtmf_accepted[i] && i < 16; i++) {
|
||||
strncpy(loc->dtmf_accepted[i], dtmf_accepted[i], 128);
|
||||
}
|
||||
loc->record_tone = "%(1000, 0, 640)";
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t ivre_playback_dtmf_buffered(switch_core_session_t *session, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_ready(channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
||||
args.input_callback = cb_on_dtmf_ignore;
|
||||
|
||||
if (macro_name) {
|
||||
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
|
||||
}
|
||||
} else {
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
switch_status_t ivre_playback(switch_core_session_t *session, ivre_data_t *loc, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_ready(channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
||||
args.input_callback = cb_on_dtmf;
|
||||
args.buf = loc;
|
||||
|
||||
if (macro_name && loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
|
||||
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
|
||||
}
|
||||
|
||||
if (switch_channel_ready(channel) && (status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK) && timeout && loc->result == RES_WAITFORMORE) {
|
||||
loc->audio_stopped = SWITCH_TRUE;
|
||||
switch_ivr_collect_digits_callback(session, &args, timeout, 0);
|
||||
if (loc->result == RES_WAITFORMORE) {
|
||||
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
|
||||
loc->result = RES_FOUND;
|
||||
} else {
|
||||
loc->result = RES_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_status_t ivre_record(switch_core_session_t *session, ivre_data_t *loc, switch_event_t *event, const char *file_path, switch_file_handle_t *fh, int max_record_len, switch_size_t *record_len) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_ready(channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
||||
args.input_callback = cb_on_dtmf;
|
||||
args.buf = loc;
|
||||
|
||||
if (loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
|
||||
loc->recorded_audio = SWITCH_TRUE;
|
||||
switch_ivr_gentones(session, loc->record_tone, 0, NULL);
|
||||
status = switch_ivr_record_file(session, fh, file_path, &args, max_record_len);
|
||||
|
||||
if (record_len) {
|
||||
*record_len = fh->samples_out / (fh->samplerate ? fh->samplerate : 8000);
|
||||
}
|
||||
|
||||
}
|
||||
if (loc->result == RES_WAITFORMORE) {
|
||||
loc->result = RES_TIMEOUT;
|
||||
}
|
||||
|
||||
} else {
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* ivr.h -- VoiceMail IVR Engine
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IVRE_H_
|
||||
#define _IVRE_H_
|
||||
|
||||
struct ivre_data {
|
||||
char dtmf_stored[128];
|
||||
int dtmf_received;
|
||||
char dtmf_accepted[16][128];
|
||||
int result;
|
||||
switch_bool_t audio_stopped;
|
||||
switch_bool_t recorded_audio;
|
||||
const char *potentialMatch;
|
||||
int potentialMatchCount;
|
||||
const char *completeMatch;
|
||||
char terminate_key;
|
||||
const char *record_tone;
|
||||
};
|
||||
typedef struct ivre_data ivre_data_t;
|
||||
|
||||
#define RES_WAITFORMORE 0
|
||||
#define RES_FOUND 1
|
||||
#define RES_INVALID 3
|
||||
#define RES_TIMEOUT 4
|
||||
#define RES_BREAK 5
|
||||
#define RES_RECORD 6
|
||||
#define RES_BUFFER_OVERFLOW 99
|
||||
|
||||
#define MAX_DTMF_SIZE_OPTION 32
|
||||
|
||||
switch_status_t ivre_init(ivre_data_t *loc, char **dtmf_accepted);
|
||||
switch_status_t ivre_playback(switch_core_session_t *session, ivre_data_t *loc, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout);
|
||||
switch_status_t ivre_record(switch_core_session_t *session, ivre_data_t *loc, switch_event_t *event, const char *file_path, switch_file_handle_t *fh, int max_record_len, switch_size_t *record_len);
|
||||
|
||||
switch_status_t ivre_playback_dtmf_buffered(switch_core_session_t *session, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout);
|
||||
#endif
|
||||
@@ -0,0 +1,869 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* menu.c -- VoiceMail Menu
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include "ivr.h"
|
||||
#include "menu.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
|
||||
/* List of available menu */
|
||||
vmivr_menu_function_t menu_list[] = {
|
||||
{"std_authenticate", vmivr_menu_authenticate},
|
||||
{"std_main_menu", vmivr_menu_main},
|
||||
{"std_navigator", vmivr_menu_navigator},
|
||||
{"std_record_name", vmivr_menu_record_name},
|
||||
{"std_set_password", vmivr_menu_set_password},
|
||||
{"std_select_greeting_slot", vmivr_menu_select_greeting_slot},
|
||||
{"std_record_greeting_with_slot", vmivr_menu_record_greeting_with_slot},
|
||||
{"std_preference", vmivr_menu_preference},
|
||||
{"std_purge", vmivr_menu_purge},
|
||||
{"std_forward", vmivr_menu_forward},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
void vmivr_menu_purge(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
vmivr_menu_t menu = { "std_menu_purge" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
if (profile->id && profile->authorized) {
|
||||
const char *exit_purge = switch_event_get_header(menu.event_settings, "Exit-Purge");
|
||||
if (switch_true(exit_purge)) {
|
||||
const char *cmd = switch_core_session_sprintf(session, "%s %s %s", profile->api_profile, profile->domain, profile->id);
|
||||
vmivr_api_execute(session, profile->api_msg_purge, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
menu_free(&menu);
|
||||
|
||||
}
|
||||
|
||||
void vmivr_menu_main(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
vmivr_menu_t menu = { "std_main_menu" };
|
||||
int retry;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys in menu '%s'\n", menu.name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
char *cmd = NULL;
|
||||
|
||||
menu_instance_init(&menu);
|
||||
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
ivre_init(&menu.ivre_d, menu.dtmfa);
|
||||
|
||||
cmd = switch_core_session_sprintf(session, "json %s %s %s %s", profile->api_profile, profile->domain, profile->id, profile->folder_name);
|
||||
jsonapi2event(session, menu.phrase_params, profile->api_msg_count, cmd);
|
||||
//initial_count_played = SWITCH_TRUE;
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "msg_count"), NULL, menu.phrase_params, NULL, 0);
|
||||
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, menu.phrase_params, NULL, menu.ivr_entry_timeout);
|
||||
|
||||
if (menu.ivre_d.result == RES_TIMEOUT) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "timeout"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_INVALID) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, menu.ivre_d.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = menu.ivr_maximum_attempts;
|
||||
|
||||
if (action) {
|
||||
if (!strncasecmp(action, "new_msg:", 8)) {
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(action+8);
|
||||
profile->folder_filter = VM_MSG_NEW;
|
||||
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
} else if (!strncasecmp(action, "saved_msg:", 10)) {
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(action+10);
|
||||
profile->folder_filter = VM_MSG_SAVED;
|
||||
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
} else if (!strcasecmp(action, "return")) { /* Return to the previous menu */
|
||||
retry = -1;
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
menu_instance_free(&menu);
|
||||
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
menu_free(&menu);
|
||||
}
|
||||
|
||||
|
||||
void vmivr_menu_navigator(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_event_t *msg_list_params = NULL;
|
||||
size_t msg_count = 0;
|
||||
size_t current_msg = 1;
|
||||
size_t next_msg = current_msg;
|
||||
size_t previous_msg = current_msg;
|
||||
char *cmd = NULL;
|
||||
int retry;
|
||||
|
||||
/* Different switch to control playback of phrases */
|
||||
switch_bool_t initial_count_played = SWITCH_FALSE;
|
||||
switch_bool_t skip_header = SWITCH_FALSE;
|
||||
switch_bool_t skip_playback = SWITCH_FALSE;
|
||||
switch_bool_t msg_deleted = SWITCH_FALSE;
|
||||
switch_bool_t msg_undeleted = SWITCH_FALSE;
|
||||
switch_bool_t msg_saved = SWITCH_FALSE;
|
||||
|
||||
vmivr_menu_t menu = { "std_navigator" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys in menu '%s'\n", menu.name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get VoiceMail List And update msg count */
|
||||
cmd = switch_core_session_sprintf(session, "json %s %s %s %s %s", profile->api_profile, profile->domain, profile->id, profile->folder_name, profile->folder_filter);
|
||||
msg_list_params = jsonapi2event(session, NULL, profile->api_msg_list, cmd);
|
||||
if (msg_list_params) {
|
||||
msg_count = atol(switch_event_get_header(msg_list_params,"VM-List-Count"));
|
||||
if (msg_count == 0) {
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "API message list return invalid result : %s(%s)\n", profile->api_msg_list, cmd);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* TODO Add Detection of new message and notify the user */
|
||||
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
char cid_buf[1024] = "";
|
||||
|
||||
menu_instance_init(&menu);
|
||||
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
previous_msg = current_msg;
|
||||
|
||||
ivre_init(&menu.ivre_d, menu.dtmfa);
|
||||
|
||||
/* Prompt related to previous Message here */
|
||||
append_event_message(session, profile, menu.phrase_params, msg_list_params, previous_msg);
|
||||
if (msg_deleted) {
|
||||
msg_deleted = SWITCH_FALSE;
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "ack"), "deleted", menu.phrase_params, NULL, 0);
|
||||
}
|
||||
if (msg_undeleted) {
|
||||
msg_undeleted = SWITCH_FALSE;
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "ack"), "undeleted", menu.phrase_params, NULL, 0);
|
||||
}
|
||||
if (msg_saved) {
|
||||
msg_saved = SWITCH_FALSE;
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "ack"), "saved", menu.phrase_params, NULL, 0);
|
||||
}
|
||||
switch_event_del_header(menu.phrase_params, "VM-Message-Flags");
|
||||
|
||||
/* Simple Protection to not go out of msg list scope */
|
||||
if (next_msg == 0) {
|
||||
next_msg = 1;
|
||||
} else if (next_msg > msg_count) {
|
||||
next_msg = msg_count;
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "no_more_messages"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
current_msg = next_msg;
|
||||
|
||||
/* Prompt related the current message */
|
||||
append_event_message(session, profile, menu.phrase_params, msg_list_params, current_msg);
|
||||
|
||||
/* Used for extra control in phrases */
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "VM-List-Count", "%"SWITCH_SIZE_T_FMT, msg_count);
|
||||
|
||||
/* Display MSG CID/Name to caller */
|
||||
switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", switch_str_nil(switch_event_get_header(menu.phrase_params, "VM-Message-Caller-Number")), switch_str_nil(switch_event_get_header(menu.phrase_params, "VM-Message-Caller-Name")));
|
||||
|
||||
msg.from = __FILE__;
|
||||
msg.string_arg = cid_buf;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
|
||||
/* Save in profile the current msg info for other menu processing AND restoration of our current position */
|
||||
profile->current_msg = current_msg;
|
||||
profile->current_msg_uuid = switch_core_session_strdup(session, switch_event_get_header(menu.phrase_params, "VM-Message-UUID"));
|
||||
|
||||
/* TODO check if msg is gone (purged by another session, notify user and auto jump to next message or something) */
|
||||
if (!skip_header) {
|
||||
if (!initial_count_played) {
|
||||
cmd = switch_core_session_sprintf(session, "json %s %s %s", profile->api_profile, profile->domain, profile->id);
|
||||
jsonapi2event(session, menu.phrase_params, profile->api_msg_count, cmd);
|
||||
initial_count_played = SWITCH_TRUE;
|
||||
// TODO ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "msg_count"), NULL, menu.phrase_params, NULL, 0);
|
||||
}
|
||||
if (msg_count > 0) {
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "say_msg_number"), NULL, menu.phrase_params, NULL, 0);
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "say_date"), NULL, menu.phrase_params, NULL, 0);
|
||||
}
|
||||
}
|
||||
if (msg_count > 0 && !skip_playback) {
|
||||
/* TODO Update the Read date of a message (When msg start, or when it listen compleatly ??? To be determined */
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "play_message"), NULL, menu.phrase_params, NULL, 0);
|
||||
}
|
||||
skip_header = SWITCH_FALSE;
|
||||
skip_playback = SWITCH_FALSE;
|
||||
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, menu.phrase_params, NULL, menu.ivr_entry_timeout);
|
||||
|
||||
if (menu.ivre_d.result == RES_TIMEOUT) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "timeout"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_INVALID) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, menu.ivre_d.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = menu.ivr_maximum_attempts;
|
||||
action:
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "skip_intro")) { /* Skip Header / Play the recording again */
|
||||
skip_header = SWITCH_TRUE;
|
||||
} else if (!strcasecmp(action, "next_msg")) { /* Next Message */
|
||||
next_msg++;
|
||||
} else if (!strcasecmp(action, "prev_msg")) { /* Previous Message */
|
||||
next_msg--;
|
||||
} else if (!strcasecmp(action, "delete_msg")) { /* Delete / Undelete Message */
|
||||
const char *msg_flags = switch_event_get_header(menu.phrase_params, "VM-Message-Flags");
|
||||
if (!msg_flags || strncasecmp(msg_flags, "delete", 6)) {
|
||||
const char *action_on_delete = switch_event_get_header(menu.event_settings, "Nav-Action-On-Delete");
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(menu.phrase_params, "VM-Message-UUID"));
|
||||
vmivr_api_execute(session, profile->api_msg_delete, cmd);
|
||||
|
||||
msg_deleted = SWITCH_TRUE;
|
||||
|
||||
if (action_on_delete) {
|
||||
action = action_on_delete;
|
||||
goto action;
|
||||
} else {
|
||||
skip_header = skip_playback = SWITCH_TRUE;
|
||||
}
|
||||
} else {
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(menu.phrase_params, "VM-Message-UUID"));
|
||||
vmivr_api_execute(session, profile->api_msg_undelete, cmd);
|
||||
|
||||
msg_undeleted = SWITCH_TRUE;
|
||||
}
|
||||
} else if (!strcasecmp(action, "save_msg")) { /* Save Message */
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(menu.phrase_params, "VM-Message-UUID"));
|
||||
vmivr_api_execute(session, profile->api_msg_save, cmd);
|
||||
|
||||
msg_saved = SWITCH_TRUE;
|
||||
} else if (!strcasecmp(action, "callback")) { /* CallBack caller */
|
||||
const char *cid_num = switch_event_get_header(menu.phrase_params, "VM-Message-Caller-Number");
|
||||
if (cid_num) {
|
||||
/* TODO add detection for private number */
|
||||
switch_core_session_execute_exten(session, cid_num, "XML", profile->domain);
|
||||
} else {
|
||||
/* TODO Some error msg that the msg doesn't contain a caller number */
|
||||
}
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
} else if (!strcasecmp(action, "return")) { /* Return */
|
||||
retry = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* IF the API to get the message returned us a COPY of the file menu.ivre_dally (temp file create from a DB or from a web server), delete it */
|
||||
if (switch_true(switch_event_get_header(menu.phrase_params, "VM-Message-Private-Local-Copy"))) {
|
||||
const char *file_path = switch_event_get_header(menu.phrase_params, "VM-Message-File-Path");
|
||||
if (file_path && unlink(file_path) != 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete temp file [%s]\n", file_path);
|
||||
}
|
||||
}
|
||||
menu_instance_free(&menu);
|
||||
}
|
||||
done:
|
||||
switch_event_destroy(&msg_list_params);
|
||||
|
||||
menu_free(&menu);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void vmivr_menu_forward(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
|
||||
vmivr_menu_t menu = { "std_forward_ask_prepend" };
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
const char *prepend_filepath = NULL;
|
||||
int retry;
|
||||
switch_bool_t forward_msg = SWITCH_FALSE;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys in menu '%s'\n", menu.name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
|
||||
menu_instance_init(&menu);
|
||||
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
ivre_init(&menu.ivre_d, menu.dtmfa);
|
||||
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, menu.phrase_params, NULL, menu.ivr_entry_timeout);
|
||||
|
||||
if (menu.ivre_d.result == RES_TIMEOUT) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "timeout"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_INVALID) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, menu.ivre_d.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = menu.ivr_maximum_attempts;
|
||||
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "return")) { /* Return to the previous menu */
|
||||
retry = -1;
|
||||
forward_msg = SWITCH_FALSE;
|
||||
} else if (!strcasecmp(action, "prepend")) { /* Prepend record msg */
|
||||
vmivr_menu_t sub_menu = { "std_record_message" };
|
||||
|
||||
const char *tmp_filepath = NULL;
|
||||
const char *record_format = NULL;
|
||||
|
||||
switch_status_t status;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &sub_menu);
|
||||
|
||||
record_format = switch_event_get_header(sub_menu.event_settings, "Record-Format");
|
||||
|
||||
tmp_filepath = generate_random_file_name(session, "voicemail_ivr", record_format);
|
||||
|
||||
status = vmivr_menu_record(session, profile, sub_menu, tmp_filepath);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
//char *cmd = switch_core_session_sprintf(session, "%s %s %s %d %s", profile->api_profile, profile->domain, profile->id, gnum, tmp_filepath);
|
||||
//char *str_num = switch_core_session_sprintf(session, "%d", gnum);
|
||||
//vmivr_api_execute(session, profile->api_pref_greeting_set, cmd);
|
||||
//ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
|
||||
prepend_filepath = tmp_filepath;
|
||||
retry = -1;
|
||||
forward_msg = SWITCH_TRUE;
|
||||
} else {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "record_failed"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
menu_free(&sub_menu);
|
||||
|
||||
} else if (!strcasecmp(action, "forward")) { /* Forward without prepend msg */
|
||||
retry = -1;
|
||||
forward_msg = SWITCH_TRUE;
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
menu_instance_free(&menu);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Ask Extension to Forward */
|
||||
if (forward_msg) {
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
const char *id = NULL;
|
||||
vmivr_menu_t sub_menu = { "std_forward_ask_extension" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &sub_menu);
|
||||
switch_event_add_header(sub_menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
id = vmivr_menu_get_input_set(session, profile, sub_menu, "X.");
|
||||
|
||||
if (id) {
|
||||
const char *cmd = switch_core_session_sprintf(session, "%s %s %s %s %s %s %s%s%s", profile->api_profile, profile->domain, profile->id, profile->current_msg_uuid, profile->domain, id, prepend_filepath?" ":"", prepend_filepath?prepend_filepath:"" );
|
||||
if (vmivr_api_execute(session, profile->api_msg_forward, cmd) == SWITCH_STATUS_SUCCESS) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(sub_menu.event_phrases, "ack"), "saved", NULL, NULL, 0);
|
||||
retry = -1;
|
||||
} else {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(sub_menu.event_phrases, "invalid_extension"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
} else {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid_input"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
menu_free(&sub_menu);
|
||||
/* TODO add Confirmation of the transfered number */
|
||||
}
|
||||
/* TODO Ask if we want to transfer the msg to more person */
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
menu_free(&menu);
|
||||
}
|
||||
|
||||
|
||||
void vmivr_menu_record_name(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_status_t status;
|
||||
vmivr_menu_t menu = { "std_record_name" };
|
||||
|
||||
const char *tmp_filepath = NULL;
|
||||
const char *record_format = NULL;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
record_format = switch_event_get_header(menu.event_settings, "Record-Format");
|
||||
|
||||
tmp_filepath = generate_random_file_name(session, "voicemail_ivr", record_format);
|
||||
|
||||
status = vmivr_menu_record(session, profile, menu, tmp_filepath);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
char *cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, tmp_filepath);
|
||||
vmivr_api_execute(session, profile->api_pref_recname_set, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void vmivr_menu_set_password(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
char *password;
|
||||
vmivr_menu_t menu = { "std_set_password" };
|
||||
const char *password_mask = NULL;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
password_mask = switch_event_get_header(menu.event_settings, "Password-Mask");
|
||||
|
||||
password = vmivr_menu_get_input_set(session, profile, menu, password_mask);
|
||||
|
||||
if (password) {
|
||||
char *cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, password);
|
||||
if (vmivr_api_execute(session, profile->api_pref_password_set, cmd)) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "password_set"), NULL, NULL, NULL, 0);
|
||||
} else {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "password_not_set"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
menu_free(&menu);
|
||||
}
|
||||
|
||||
void vmivr_menu_authenticate(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
vmivr_menu_t menu = { "std_authenticate" };
|
||||
int retry;
|
||||
const char *auth_var = NULL;
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
if (profile->id && (auth_var = switch_channel_get_variable(channel, "voicemail_authorized")) && switch_true(auth_var)) {
|
||||
profile->authorized = SWITCH_TRUE;
|
||||
}
|
||||
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0 && profile->authorized == SWITCH_FALSE; retry--) {
|
||||
const char *id = profile->id, *password = NULL;
|
||||
char *cmd = NULL;
|
||||
const char *password_mask = switch_event_get_header(menu.event_settings, "Password-Mask");
|
||||
const char *user_mask = switch_event_get_header(menu.event_settings, "User-Mask");
|
||||
if (!id) {
|
||||
vmivr_menu_t sub_menu = { "std_authenticate_ask_user" };
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &sub_menu);
|
||||
|
||||
switch_event_add_header(sub_menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
id = vmivr_menu_get_input_set(session, profile, sub_menu, user_mask);
|
||||
menu_free(&sub_menu);
|
||||
}
|
||||
if (!password) {
|
||||
vmivr_menu_t sub_menu = { "std_authenticate_ask_password" };
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &sub_menu);
|
||||
|
||||
switch_event_add_header(sub_menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
password = vmivr_menu_get_input_set(session, profile, sub_menu, password_mask);
|
||||
menu_free(&sub_menu);
|
||||
}
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, id, password);
|
||||
|
||||
if (vmivr_api_execute(session, profile->api_auth_login, cmd) == SWITCH_STATUS_SUCCESS) {
|
||||
profile->id = id;
|
||||
profile->authorized = SWITCH_TRUE;
|
||||
} else {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "fail_auth"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
menu_free(&menu);
|
||||
}
|
||||
|
||||
void vmivr_menu_select_greeting_slot(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
vmivr_menu_t menu = { "std_select_greeting_slot" };
|
||||
|
||||
const char *result;
|
||||
int gnum = -1;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
result = vmivr_menu_get_input_set(session, profile, menu, "X");
|
||||
|
||||
if (result)
|
||||
gnum = atoi(result);
|
||||
if (gnum != -1) {
|
||||
char * cmd = switch_core_session_sprintf(session, "%s %s %s %d", profile->api_profile, profile->domain, profile->id, gnum);
|
||||
if (vmivr_api_execute(session, profile->api_pref_greeting_set, cmd) == SWITCH_STATUS_SUCCESS) {
|
||||
char *str_num = switch_core_session_sprintf(session, "%d", gnum);
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
|
||||
} else {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid_slot"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
menu_free(&menu);
|
||||
}
|
||||
|
||||
void vmivr_menu_record_greeting_with_slot(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
|
||||
vmivr_menu_t menu = { "std_record_greeting_with_slot" };
|
||||
|
||||
const char *result;
|
||||
int gnum = -1;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
result = vmivr_menu_get_input_set(session, profile, menu, "X");
|
||||
|
||||
if (result)
|
||||
gnum = atoi(result);
|
||||
|
||||
/* If user entered 0, we don't accept it */
|
||||
if (gnum > 0) {
|
||||
vmivr_menu_t sub_menu = { "std_record_greeting" };
|
||||
char *tmp_filepath = NULL;
|
||||
const char *record_format = NULL;
|
||||
|
||||
switch_status_t status;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &sub_menu);
|
||||
|
||||
record_format = switch_event_get_header(menu.event_settings, "Record-Format");
|
||||
|
||||
tmp_filepath = generate_random_file_name(session, "voicemail_ivr", record_format);
|
||||
|
||||
status = vmivr_menu_record(session, profile, sub_menu, tmp_filepath);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
char *cmd = switch_core_session_sprintf(session, "%s %s %s %d %s", profile->api_profile, profile->domain, profile->id, gnum, tmp_filepath);
|
||||
char *str_num = switch_core_session_sprintf(session, "%d", gnum);
|
||||
vmivr_api_execute(session, profile->api_pref_greeting_set, cmd);
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
|
||||
}
|
||||
menu_free(&sub_menu);
|
||||
|
||||
}
|
||||
|
||||
menu_free(&menu);
|
||||
|
||||
}
|
||||
|
||||
void vmivr_menu_preference(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
int retry;
|
||||
|
||||
vmivr_menu_t menu = { "std_preference" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
menu_init(profile, &menu);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys in menu '%s'\n", menu.name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
|
||||
menu_instance_init(&menu);
|
||||
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
ivre_init(&menu.ivre_d, menu.dtmfa);
|
||||
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, menu.phrase_params, NULL, menu.ivr_entry_timeout);
|
||||
|
||||
if (menu.ivre_d.result == RES_TIMEOUT) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "timeout"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_INVALID) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, menu.ivre_d.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = menu.ivr_maximum_attempts;
|
||||
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "return")) { /* Return to the previous menu */
|
||||
retry = -1;
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
menu_instance_free(&menu);
|
||||
}
|
||||
|
||||
end:
|
||||
menu_free(&menu);
|
||||
}
|
||||
|
||||
char *vmivr_menu_get_input_set(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_t menu, const char *input_mask) {
|
||||
char *result = NULL;
|
||||
int retry;
|
||||
const char *terminate_key = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys in menu '%s'\n", menu.name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
terminate_key = switch_event_get_header(menu.event_keys_action, "ivrengine:terminate_entry");
|
||||
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
int i;
|
||||
|
||||
menu_instance_init(&menu);
|
||||
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
/* Find the last entry and append this one to it */
|
||||
for (i=0; menu.dtmfa[i] && i < 16; i++){
|
||||
}
|
||||
menu.dtmfa[i] = (char *) input_mask;
|
||||
|
||||
ivre_init(&menu.ivre_d, menu.dtmfa);
|
||||
if (terminate_key) {
|
||||
menu.ivre_d.terminate_key = terminate_key[0];
|
||||
}
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "instructions"), NULL, menu.phrase_params, NULL, menu.ivr_entry_timeout);
|
||||
|
||||
if (menu.ivre_d.result == RES_TIMEOUT) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "timeout"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_INVALID) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
|
||||
/* Reset the try count */
|
||||
retry = menu.ivr_maximum_attempts;
|
||||
|
||||
if (!strncasecmp(menu.ivre_d.completeMatch, input_mask, 1)) {
|
||||
result = switch_core_session_strdup(session, menu.ivre_d.dtmf_stored);
|
||||
retry = -1;
|
||||
|
||||
}
|
||||
}
|
||||
menu_instance_free(&menu);
|
||||
}
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
switch_status_t vmivr_menu_record(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_t menu, const char *file_name) {
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
int retry;
|
||||
|
||||
switch_bool_t record_prompt = SWITCH_TRUE;
|
||||
switch_bool_t listen_recording = SWITCH_FALSE;
|
||||
switch_bool_t play_instruction = SWITCH_TRUE;
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys in menu '%s'\n", menu.name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (retry = menu.ivr_maximum_attempts; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
switch_file_handle_t fh = { 0 };
|
||||
const char *rec_silence_hits = switch_event_get_header(menu.event_settings, "Record-Silence-Hits");
|
||||
const char *rec_silence_threshold = switch_event_get_header(menu.event_settings, "Record-Silence-Threshold");
|
||||
const char *rec_silence_samplerate = switch_event_get_header(menu.event_settings, "Record-Sample-Rate");
|
||||
const char *rec_maximum_length = switch_event_get_header(menu.event_settings, "Record-Maximum-Length");
|
||||
const char *rec_minimum_length = switch_event_get_header(menu.event_settings, "Record-Minimum-Length");
|
||||
switch_size_t record_length = 0;
|
||||
|
||||
/* Prepare Recording File Handle */
|
||||
fh.thresh = atoi(rec_silence_threshold);
|
||||
fh.silence_hits = atoi(rec_silence_hits);
|
||||
if (rec_silence_samplerate) {
|
||||
fh.samplerate = atoi(rec_silence_samplerate);
|
||||
}
|
||||
|
||||
menu_instance_init(&menu);
|
||||
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "IVR-Retry-Left", "%d", retry);
|
||||
|
||||
ivre_init(&menu.ivre_d, menu.dtmfa);
|
||||
|
||||
if (record_prompt) {
|
||||
if (play_instruction) {
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "instructions"), NULL, menu.phrase_params, NULL, 0);
|
||||
}
|
||||
play_instruction = SWITCH_TRUE;
|
||||
|
||||
ivre_record(session, &menu.ivre_d, menu.phrase_params, file_name, &fh, atoi(rec_maximum_length), &record_length);
|
||||
} else {
|
||||
if (listen_recording) {
|
||||
switch_event_add_header(menu.phrase_params, SWITCH_STACK_BOTTOM, "VM-Record-File-Path", "%s", file_name);
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "play_recording"), NULL, menu.phrase_params, NULL, 0);
|
||||
listen_recording = SWITCH_FALSE;
|
||||
|
||||
}
|
||||
ivre_playback(session, &menu.ivre_d, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, menu.phrase_params, NULL, menu.ivr_entry_timeout);
|
||||
}
|
||||
|
||||
if (menu.ivre_d.recorded_audio) {
|
||||
/* Reset the try count */
|
||||
retry = menu.ivr_maximum_attempts;
|
||||
|
||||
if (rec_minimum_length && record_length < atoi(rec_minimum_length)) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "too_short"), NULL, NULL, NULL, 0);
|
||||
unlink(file_name);
|
||||
} else {
|
||||
record_prompt = SWITCH_FALSE;
|
||||
}
|
||||
|
||||
} else if (menu.ivre_d.result == RES_TIMEOUT) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "timeout"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_INVALID) {
|
||||
ivre_playback_dtmf_buffered(session, switch_event_get_header(menu.event_phrases, "invalid"), NULL, NULL, NULL, 0);
|
||||
} else if (menu.ivre_d.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, menu.ivre_d.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = menu.ivr_maximum_attempts;
|
||||
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "listen")) { /* Listen */
|
||||
listen_recording = SWITCH_TRUE;
|
||||
|
||||
} else if (!strcasecmp(action, "save")) {
|
||||
retry = -1;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
} else if (!strcasecmp(action, "rerecord")) {
|
||||
record_prompt = SWITCH_TRUE;
|
||||
|
||||
} else if (!strcasecmp(action, "skip_instruction")) { /* Skip Recording Greeting */
|
||||
play_instruction = SWITCH_FALSE;
|
||||
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
} else if (!strcasecmp(action, "return")) { /* Return */
|
||||
retry = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
menu_instance_free(&menu);
|
||||
}
|
||||
|
||||
end:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void (*vmivr_get_menu_function(const char *menu_name))(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
int i = 0;
|
||||
|
||||
if (menu_name) {
|
||||
for (i=0; menu_list[i].name ; i++) {
|
||||
if (!strcasecmp(menu_list[i].name, menu_name)) {
|
||||
return menu_list[i].pt2Func;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* menu.h -- VoiceMail IVR Menu Include
|
||||
*
|
||||
*/
|
||||
#ifndef _MENU_H_
|
||||
#define _MENU_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void vmivr_menu_purge(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_authenticate(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_main(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_navigator(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_record_name(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_set_password(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_select_greeting_slot(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_record_greeting_with_slot(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_preference(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void vmivr_menu_forward(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
|
||||
switch_status_t vmivr_menu_record(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_t menu, const char *file_name);
|
||||
char *vmivr_menu_get_input_set(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_t menu, const char *input_mask);
|
||||
|
||||
|
||||
struct vmivr_menu_function {
|
||||
const char *name;
|
||||
void (*pt2Func)(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
|
||||
};
|
||||
typedef struct vmivr_menu_function vmivr_menu_function_t;
|
||||
|
||||
extern vmivr_menu_function_t menu_list[];
|
||||
|
||||
void (*vmivr_get_menu_function(const char *menu_name))(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
|
||||
#endif /* _MENU_H_ */
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* mod_voicemail_ivr.c -- VoiceMail IVR System
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "menu.h"
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_voicemail_ivr_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_voicemail_ivr_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_ivr_load);
|
||||
|
||||
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
|
||||
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
|
||||
*/
|
||||
SWITCH_MODULE_DEFINITION(mod_voicemail_ivr, mod_voicemail_ivr_load, mod_voicemail_ivr_shutdown, NULL);
|
||||
|
||||
|
||||
#define VMIVR_DESC "voicemail_ivr"
|
||||
#define VMIVR_USAGE "<check> profile domain [id]"
|
||||
|
||||
SWITCH_STANDARD_APP(voicemail_ivr_function)
|
||||
{
|
||||
const char *id = NULL;
|
||||
const char *domain = NULL;
|
||||
const char *profile_name = NULL;
|
||||
vmivr_profile_t *profile = NULL;
|
||||
char *argv[6] = { 0 };
|
||||
char *mydata = NULL;
|
||||
|
||||
if (!zstr(data)) {
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[1])
|
||||
profile_name = argv[1];
|
||||
|
||||
if (argv[2])
|
||||
domain = argv[2];
|
||||
|
||||
if (!strcasecmp(argv[0], "check")) {
|
||||
if (argv[3])
|
||||
id = argv[3];
|
||||
|
||||
if (domain && profile_name) {
|
||||
profile = get_profile(session, profile_name);
|
||||
|
||||
if (profile) {
|
||||
void (*fPtrAuth)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(profile->menu_check_auth);
|
||||
void (*fPtrMain)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(profile->menu_check_main);
|
||||
void (*fPtrTerminate)(switch_core_session_t *session, vmivr_profile_t *profile) = vmivr_get_menu_function(profile->menu_check_terminate);
|
||||
|
||||
profile->domain = domain;
|
||||
profile->id = id;
|
||||
|
||||
if (fPtrAuth && !profile->authorized) {
|
||||
fPtrAuth(session, profile);
|
||||
}
|
||||
|
||||
if (fPtrMain && profile->authorized) {
|
||||
fPtrMain(session, profile);
|
||||
}
|
||||
if (fPtrTerminate) {
|
||||
fPtrTerminate(session, profile);
|
||||
}
|
||||
free_profile(profile);
|
||||
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' not found\n", profile_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Macro expands to: switch_status_t mod_voicemail_ivr_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_ivr_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "voicemail_ivr", "voicemail_ivr", VMIVR_DESC, voicemail_ivr_function, VMIVR_USAGE, SAF_NONE);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
Called when the system shuts down
|
||||
Macro expands to: switch_status_t mod_voicemail_ivr_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_voicemail_ivr_shutdown)
|
||||
{
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* utils.c -- VoiceMail IVR / Different utility that might need to go into the core (after cleanup)
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
switch_status_t vmivr_merge_media_files(const char** inputs, const char *output, int rate) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_file_handle_t fh_output = { 0 };
|
||||
int channels = 1;
|
||||
int j = 0;
|
||||
|
||||
if (switch_core_file_open(&fh_output, output, channels, rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open %s\n", output);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (j = 0; inputs[j] != NULL && j < 128 && status == SWITCH_STATUS_SUCCESS; j++) {
|
||||
switch_file_handle_t fh_input = { 0 };
|
||||
char buf[2048];
|
||||
switch_size_t len = sizeof(buf) / 2;
|
||||
|
||||
if (switch_core_file_open(&fh_input, inputs[j], channels, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open %s\n", inputs[j]);
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
break;
|
||||
}
|
||||
|
||||
while (switch_core_file_read(&fh_input, buf, &len) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_core_file_write(&fh_output, buf, &len) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Write error\n");
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fh_input.file_interface) {
|
||||
switch_core_file_close(&fh_input);
|
||||
}
|
||||
}
|
||||
|
||||
if (fh_output.file_interface) {
|
||||
switch_core_file_close(&fh_output);
|
||||
}
|
||||
end:
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_event_t *jsonapi2event(switch_core_session_t *session, switch_event_t *apply_event, const char *api, const char *data) {
|
||||
switch_event_t *phrases_event = NULL;
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_api_execute(api, data, session, &stream);
|
||||
switch_event_create_json(&phrases_event, (char *) stream.data);
|
||||
switch_safe_free(stream.data);
|
||||
|
||||
if (apply_event) {
|
||||
switch_event_header_t *hp;
|
||||
for (hp = phrases_event->headers; hp; hp = hp->next) {
|
||||
if (!strncasecmp(hp->name, "VM-", 3)) {
|
||||
switch_event_add_header(apply_event, SWITCH_STACK_BOTTOM, hp->name, "%s", hp->value);
|
||||
}
|
||||
}
|
||||
switch_event_destroy(&phrases_event);
|
||||
phrases_event = apply_event;
|
||||
|
||||
}
|
||||
|
||||
return phrases_event;
|
||||
}
|
||||
|
||||
char *generate_random_file_name(switch_core_session_t *session, const char *mod_name, const char *file_extension) {
|
||||
char rand_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = "";
|
||||
switch_uuid_t srand_uuid;
|
||||
|
||||
switch_uuid_get(&srand_uuid);
|
||||
switch_uuid_format(rand_uuid, &srand_uuid);
|
||||
|
||||
return switch_core_session_sprintf(session, "%s%s%s_%s.%s", SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, mod_name, rand_uuid, file_extension);
|
||||
|
||||
}
|
||||
|
||||
switch_status_t vmivr_api_execute(switch_core_session_t *session, const char *apiname, const char *arguments) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_api_execute(apiname, arguments, session, &stream);
|
||||
if (!strncasecmp(stream.data, "-ERR", 4)) {
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
}
|
||||
switch_safe_free(stream.data);
|
||||
return status;
|
||||
}
|
||||
|
||||
void append_event_message(switch_core_session_t *session, vmivr_profile_t *profile, switch_event_t *phrase_params, switch_event_t *msg_list_event, size_t current_msg) {
|
||||
|
||||
char *varname;
|
||||
char *apicmd;
|
||||
char *total_msg = NULL;
|
||||
|
||||
if (!msg_list_event || !(total_msg = switch_event_get_header(msg_list_event, "VM-List-Count")) || current_msg > atoi(total_msg)) {
|
||||
/* TODO Error MSG */
|
||||
return;
|
||||
}
|
||||
|
||||
varname = switch_mprintf("VM-List-Message-%" SWITCH_SIZE_T_FMT "-UUID", current_msg);
|
||||
apicmd = switch_mprintf("json %s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(msg_list_event, varname));
|
||||
|
||||
switch_safe_free(varname);
|
||||
|
||||
jsonapi2event(session, phrase_params, profile->api_msg_get, apicmd);
|
||||
|
||||
/* TODO Set these 2 header correctly */
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Type", "%s", "new");
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Number", "%"SWITCH_SIZE_T_FMT, current_msg);
|
||||
|
||||
switch_event_add_header_string(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Private-Local-Copy", "False");
|
||||
|
||||
switch_safe_free(apicmd);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* utils.c -- VoiceMail IVR / Different utility that might need to go into the core (after cleanup)
|
||||
*
|
||||
*/
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void append_event_message(switch_core_session_t *session, vmivr_profile_t *profile, switch_event_t *phrase_params, switch_event_t *msg_list_event, size_t current_msg);
|
||||
char *generate_random_file_name(switch_core_session_t *session, const char *mod_name, const char *file_extension);
|
||||
switch_event_t *jsonapi2event(switch_core_session_t *session, switch_event_t *apply_event, const char *api, const char *data);
|
||||
switch_status_t vmivr_merge_media_files(const char** inputs, const char *output, int rate);
|
||||
switch_status_t vmivr_api_execute(switch_core_session_t *session, const char *apiname, const char *arguments);
|
||||
#endif /* _UTIL_H_ */
|
||||
|
||||
@@ -105,7 +105,7 @@ static switch_status_t tts_commandline_speech_open(switch_speech_handle_t *sh, c
|
||||
/* Construct temporary file name with a new UUID */
|
||||
switch_uuid_get(&uuid);
|
||||
switch_uuid_format(uuid_str, &uuid);
|
||||
switch_snprintf(outfile, sizeof(outfile), "%s%s.tmp.wav", SWITCH_GLOBAL_dirs.temp_dir, uuid_str);
|
||||
switch_snprintf(outfile, sizeof(outfile), "%s%s%s.tmp.wav", SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, uuid_str);
|
||||
info->file = switch_core_strdup(sh->memory_pool, outfile);
|
||||
|
||||
info->fh = (switch_file_handle_t *) switch_core_alloc(sh->memory_pool, sizeof(switch_file_handle_t));
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
Copyright (c) 2011, The WebRTC project authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the name of Google nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,71 @@
|
||||
BASE=../../../..
|
||||
|
||||
LOCAL_SOURCES=arith_routines.c\
|
||||
arith_routines_hist.c\
|
||||
arith_routines_logist.c\
|
||||
auto_correlation.c\
|
||||
auto_corr_to_refl_coef.c\
|
||||
bandwidth_estimator.c\
|
||||
complex_bit_reverse.c\
|
||||
complex_fft.c\
|
||||
copy_set_operations.c\
|
||||
crc.c\
|
||||
cross_correlation.c\
|
||||
decode_bwe.c\
|
||||
decode.c\
|
||||
division_operations.c\
|
||||
dot_product_with_scale.c\
|
||||
downsample_fast.c\
|
||||
encode.c\
|
||||
encode_lpc_swb.c\
|
||||
energy.c\
|
||||
entropy_coding.c\
|
||||
fft.c\
|
||||
filter_ar.c\
|
||||
filter_ar_fast_q12.c\
|
||||
filterbanks.c\
|
||||
filterbank_tables.c\
|
||||
filter_functions.c\
|
||||
filter_ma_fast_q12.c\
|
||||
get_hanning_window.c\
|
||||
get_scaling_square.c\
|
||||
ilbc_specific_functions.c\
|
||||
intialize.c\
|
||||
isac.c\
|
||||
lattice.c\
|
||||
levinson_durbin.c\
|
||||
lpc_analysis.c\
|
||||
lpc_gain_swb_tables.c\
|
||||
lpc_shape_swb12_tables.c\
|
||||
lpc_shape_swb16_tables.c\
|
||||
lpc_tables.c\
|
||||
lpc_to_refl_coef.c\
|
||||
min_max_operations.c\
|
||||
min_max_operations_neon.c\
|
||||
pitch_estimator.c\
|
||||
pitch_filter.c\
|
||||
pitch_gain_tables.c\
|
||||
pitch_lag_tables.c\
|
||||
randomization_functions.c\
|
||||
refl_coef_to_lpc.c\
|
||||
resample_48khz.c\
|
||||
resample_by_2.c\
|
||||
resample_by_2_internal.c\
|
||||
resample.c\
|
||||
resample_fractional.c\
|
||||
spectrum_ar_model_tables.c\
|
||||
splitting_filter.c\
|
||||
spl_sqrt.c\
|
||||
spl_sqrt_floor.c\
|
||||
spl_version.c\
|
||||
sqrt_of_one_minus_x_squared.c\
|
||||
transform.c\
|
||||
vector_scaling_operations.c\
|
||||
webrtc_fft_t_1024_8.c\
|
||||
webrtc_fft_t_rad.c ""
|
||||
|
||||
LOCAL_OBJS=$(shell echo $(LOCAL_SOURCES) | sed "s/.c /.o /g")
|
||||
LOCAL_CFLAGS=-w -I.
|
||||
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the WebRTC code package.
|
||||
|
||||
Google hereby grants to you a perpetual, worldwide, non-exclusive,
|
||||
no-charge, irrevocable (except as stated in this section) patent
|
||||
license to make, have made, use, offer to sell, sell, import,
|
||||
transfer, and otherwise run, modify and propagate the contents of this
|
||||
implementation of the WebRTC code package, where such license applies
|
||||
only to those patent claims, both currently owned by Google and
|
||||
acquired in the future, licensable by Google that are necessarily
|
||||
infringed by this implementation of the WebRTC code package. This
|
||||
grant does not include claims that would be infringed only as a
|
||||
consequence of further modification of this implementation. If you or
|
||||
your agent or exclusive licensee institute or order or agree to the
|
||||
institution of patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that this
|
||||
implementation of the WebRTC code package or any code incorporated
|
||||
within this implementation of the WebRTC code package constitutes
|
||||
direct or contributory patent infringement, or inducement of patent
|
||||
infringement, then any patent rights granted to you under this License
|
||||
for this implementation of the WebRTC code package shall terminate as
|
||||
of the date such litigation is filed.
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "arith_routines.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
/*
|
||||
* terminate and return byte stream;
|
||||
* returns the number of bytes in the stream
|
||||
*/
|
||||
int WebRtcIsac_EncTerminate(Bitstr *streamdata) /* in-/output struct containing bitstream */
|
||||
{
|
||||
WebRtc_UWord8 *stream_ptr;
|
||||
|
||||
|
||||
/* point to the right place in the stream buffer */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
|
||||
/* find minimum length (determined by current interval width) */
|
||||
if ( streamdata->W_upper > 0x01FFFFFF )
|
||||
{
|
||||
streamdata->streamval += 0x01000000;
|
||||
/* add carry to buffer */
|
||||
if (streamdata->streamval < 0x01000000)
|
||||
{
|
||||
/* propagate carry */
|
||||
while ( !(++(*--stream_ptr)) );
|
||||
/* put pointer back to the old value */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
}
|
||||
/* write remaining data to bitstream */
|
||||
*stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24);
|
||||
}
|
||||
else
|
||||
{
|
||||
streamdata->streamval += 0x00010000;
|
||||
/* add carry to buffer */
|
||||
if (streamdata->streamval < 0x00010000)
|
||||
{
|
||||
/* propagate carry */
|
||||
while ( !(++(*--stream_ptr)) );
|
||||
/* put pointer back to the old value */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
}
|
||||
/* write remaining data to bitstream */
|
||||
*stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24);
|
||||
*stream_ptr++ = (WebRtc_UWord8) ((streamdata->streamval >> 16) & 0x00FF);
|
||||
}
|
||||
|
||||
/* calculate stream length */
|
||||
return (int)(stream_ptr - streamdata->stream);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* arith_routines.h
|
||||
*
|
||||
* Functions for arithmetic coding.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
|
||||
int WebRtcIsac_EncLogisticMulti2(
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
WebRtc_Word16 *dataQ7, /* input: data vector */
|
||||
const WebRtc_UWord16 *env, /* input: side info vector defining the width of the pdf */
|
||||
const int N, /* input: data vector length */
|
||||
const WebRtc_Word16 isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
|
||||
|
||||
/* returns the number of bytes in the stream */
|
||||
int WebRtcIsac_EncTerminate(Bitstr *streamdata); /* in-/output struct containing bitstream */
|
||||
|
||||
/* returns the number of bytes in the stream so far */
|
||||
int WebRtcIsac_DecLogisticMulti2(
|
||||
WebRtc_Word16 *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const WebRtc_UWord16 *env, /* input: side info vector defining the width of the pdf */
|
||||
const WebRtc_Word16 *dither, /* input: dither vector */
|
||||
const int N, /* input: data vector length */
|
||||
const WebRtc_Word16 isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
|
||||
|
||||
void WebRtcIsac_EncHistMulti(
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const int *data, /* input: data vector */
|
||||
const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */
|
||||
const int N); /* input: data vector length */
|
||||
|
||||
int WebRtcIsac_DecHistBisectMulti(
|
||||
int *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */
|
||||
const WebRtc_UWord16 *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
|
||||
const int N); /* input: data vector length */
|
||||
|
||||
int WebRtcIsac_DecHistOneStepMulti(
|
||||
int *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */
|
||||
const WebRtc_UWord16 *init_index,/* input: vector of initial cdf table search entries */
|
||||
const int N); /* input: data vector length */
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
#include "arith_routines.h"
|
||||
|
||||
|
||||
/*
|
||||
* code symbols into arithmetic bytestream
|
||||
*/
|
||||
void WebRtcIsac_EncHistMulti(Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const int *data, /* input: data vector */
|
||||
const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */
|
||||
const int N) /* input: data vector length */
|
||||
{
|
||||
WebRtc_UWord32 W_lower, W_upper;
|
||||
WebRtc_UWord32 W_upper_LSB, W_upper_MSB;
|
||||
WebRtc_UWord8 *stream_ptr;
|
||||
WebRtc_UWord8 *stream_ptr_carry;
|
||||
WebRtc_UWord32 cdf_lo, cdf_hi;
|
||||
int k;
|
||||
|
||||
|
||||
/* point to beginning of stream buffer */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
W_upper = streamdata->W_upper;
|
||||
|
||||
for (k=N; k>0; k--)
|
||||
{
|
||||
/* fetch cdf_lower and cdf_upper from cdf tables */
|
||||
cdf_lo = (WebRtc_UWord32) *(*cdf + *data);
|
||||
cdf_hi = (WebRtc_UWord32) *(*cdf++ + *data++ + 1);
|
||||
|
||||
/* update interval */
|
||||
W_upper_LSB = W_upper & 0x0000FFFF;
|
||||
W_upper_MSB = W_upper >> 16;
|
||||
W_lower = W_upper_MSB * cdf_lo;
|
||||
W_lower += (W_upper_LSB * cdf_lo) >> 16;
|
||||
W_upper = W_upper_MSB * cdf_hi;
|
||||
W_upper += (W_upper_LSB * cdf_hi) >> 16;
|
||||
|
||||
/* shift interval such that it begins at zero */
|
||||
W_upper -= ++W_lower;
|
||||
|
||||
/* add integer to bitstream */
|
||||
streamdata->streamval += W_lower;
|
||||
|
||||
/* handle carry */
|
||||
if (streamdata->streamval < W_lower)
|
||||
{
|
||||
/* propagate carry */
|
||||
stream_ptr_carry = stream_ptr;
|
||||
while (!(++(*--stream_ptr_carry)));
|
||||
}
|
||||
|
||||
/* renormalize interval, store most significant byte of streamval and update streamval */
|
||||
while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */
|
||||
{
|
||||
W_upper <<= 8;
|
||||
*stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24);
|
||||
streamdata->streamval <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate new stream_index */
|
||||
streamdata->stream_index = (int)(stream_ptr - streamdata->stream);
|
||||
streamdata->W_upper = W_upper;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* function to decode more symbols from the arithmetic bytestream, using method of bisection
|
||||
* cdf tables should be of size 2^k-1 (which corresponds to an alphabet size of 2^k-2)
|
||||
*/
|
||||
int WebRtcIsac_DecHistBisectMulti(int *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */
|
||||
const WebRtc_UWord16 *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
|
||||
const int N) /* input: data vector length */
|
||||
{
|
||||
WebRtc_UWord32 W_lower, W_upper;
|
||||
WebRtc_UWord32 W_tmp;
|
||||
WebRtc_UWord32 W_upper_LSB, W_upper_MSB;
|
||||
WebRtc_UWord32 streamval;
|
||||
const WebRtc_UWord8 *stream_ptr;
|
||||
const WebRtc_UWord16 *cdf_ptr;
|
||||
int size_tmp;
|
||||
int k;
|
||||
|
||||
W_lower = 0; //to remove warning -DH
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
W_upper = streamdata->W_upper;
|
||||
if (W_upper == 0)
|
||||
/* Should not be possible in normal operation */
|
||||
return -2;
|
||||
|
||||
if (streamdata->stream_index == 0) /* first time decoder is called for this stream */
|
||||
{
|
||||
/* read first word from bytestream */
|
||||
streamval = *stream_ptr << 24;
|
||||
streamval |= *++stream_ptr << 16;
|
||||
streamval |= *++stream_ptr << 8;
|
||||
streamval |= *++stream_ptr;
|
||||
} else {
|
||||
streamval = streamdata->streamval;
|
||||
}
|
||||
|
||||
for (k=N; k>0; k--)
|
||||
{
|
||||
/* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
|
||||
W_upper_LSB = W_upper & 0x0000FFFF;
|
||||
W_upper_MSB = W_upper >> 16;
|
||||
|
||||
/* start halfway the cdf range */
|
||||
size_tmp = *cdf_size++ >> 1;
|
||||
cdf_ptr = *cdf + (size_tmp - 1);
|
||||
|
||||
/* method of bisection */
|
||||
for ( ;; )
|
||||
{
|
||||
W_tmp = W_upper_MSB * *cdf_ptr;
|
||||
W_tmp += (W_upper_LSB * *cdf_ptr) >> 16;
|
||||
size_tmp >>= 1;
|
||||
if (size_tmp == 0) break;
|
||||
if (streamval > W_tmp)
|
||||
{
|
||||
W_lower = W_tmp;
|
||||
cdf_ptr += size_tmp;
|
||||
} else {
|
||||
W_upper = W_tmp;
|
||||
cdf_ptr -= size_tmp;
|
||||
}
|
||||
}
|
||||
if (streamval > W_tmp)
|
||||
{
|
||||
W_lower = W_tmp;
|
||||
*data++ = (int)(cdf_ptr - *cdf++);
|
||||
} else {
|
||||
W_upper = W_tmp;
|
||||
*data++ = (int)(cdf_ptr - *cdf++ - 1);
|
||||
}
|
||||
|
||||
/* shift interval to start at zero */
|
||||
W_upper -= ++W_lower;
|
||||
|
||||
/* add integer to bitstream */
|
||||
streamval -= W_lower;
|
||||
|
||||
/* renormalize interval and update streamval */
|
||||
while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */
|
||||
{
|
||||
/* read next byte from stream */
|
||||
streamval = (streamval << 8) | *++stream_ptr;
|
||||
W_upper <<= 8;
|
||||
}
|
||||
|
||||
if (W_upper == 0)
|
||||
/* Should not be possible in normal operation */
|
||||
return -2;
|
||||
|
||||
|
||||
}
|
||||
|
||||
streamdata->stream_index = (int)(stream_ptr - streamdata->stream);
|
||||
streamdata->W_upper = W_upper;
|
||||
streamdata->streamval = streamval;
|
||||
|
||||
|
||||
/* find number of bytes in original stream (determined by current interval width) */
|
||||
if ( W_upper > 0x01FFFFFF )
|
||||
return streamdata->stream_index - 2;
|
||||
else
|
||||
return streamdata->stream_index - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* function to decode more symbols from the arithmetic bytestream, taking single step up or
|
||||
* down at a time
|
||||
* cdf tables can be of arbitrary size, but large tables may take a lot of iterations
|
||||
*/
|
||||
int WebRtcIsac_DecHistOneStepMulti(int *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */
|
||||
const WebRtc_UWord16 *init_index, /* input: vector of initial cdf table search entries */
|
||||
const int N) /* input: data vector length */
|
||||
{
|
||||
WebRtc_UWord32 W_lower, W_upper;
|
||||
WebRtc_UWord32 W_tmp;
|
||||
WebRtc_UWord32 W_upper_LSB, W_upper_MSB;
|
||||
WebRtc_UWord32 streamval;
|
||||
const WebRtc_UWord8 *stream_ptr;
|
||||
const WebRtc_UWord16 *cdf_ptr;
|
||||
int k;
|
||||
|
||||
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
W_upper = streamdata->W_upper;
|
||||
if (W_upper == 0)
|
||||
/* Should not be possible in normal operation */
|
||||
return -2;
|
||||
|
||||
if (streamdata->stream_index == 0) /* first time decoder is called for this stream */
|
||||
{
|
||||
/* read first word from bytestream */
|
||||
streamval = *stream_ptr << 24;
|
||||
streamval |= *++stream_ptr << 16;
|
||||
streamval |= *++stream_ptr << 8;
|
||||
streamval |= *++stream_ptr;
|
||||
} else {
|
||||
streamval = streamdata->streamval;
|
||||
}
|
||||
|
||||
|
||||
for (k=N; k>0; k--)
|
||||
{
|
||||
/* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
|
||||
W_upper_LSB = W_upper & 0x0000FFFF;
|
||||
W_upper_MSB = W_upper >> 16;
|
||||
|
||||
/* start at the specified table entry */
|
||||
cdf_ptr = *cdf + (*init_index++);
|
||||
W_tmp = W_upper_MSB * *cdf_ptr;
|
||||
W_tmp += (W_upper_LSB * *cdf_ptr) >> 16;
|
||||
if (streamval > W_tmp)
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
W_lower = W_tmp;
|
||||
if (cdf_ptr[0]==65535)
|
||||
/* range check */
|
||||
return -3;
|
||||
W_tmp = W_upper_MSB * *++cdf_ptr;
|
||||
W_tmp += (W_upper_LSB * *cdf_ptr) >> 16;
|
||||
if (streamval <= W_tmp) break;
|
||||
}
|
||||
W_upper = W_tmp;
|
||||
*data++ = (int)(cdf_ptr - *cdf++ - 1);
|
||||
} else {
|
||||
for ( ;; )
|
||||
{
|
||||
W_upper = W_tmp;
|
||||
--cdf_ptr;
|
||||
if (cdf_ptr<*cdf) {
|
||||
/* range check */
|
||||
return -3;
|
||||
}
|
||||
W_tmp = W_upper_MSB * *cdf_ptr;
|
||||
W_tmp += (W_upper_LSB * *cdf_ptr) >> 16;
|
||||
if (streamval > W_tmp) break;
|
||||
}
|
||||
W_lower = W_tmp;
|
||||
*data++ = (int)(cdf_ptr - *cdf++);
|
||||
}
|
||||
|
||||
/* shift interval to start at zero */
|
||||
W_upper -= ++W_lower;
|
||||
/* add integer to bitstream */
|
||||
streamval -= W_lower;
|
||||
|
||||
/* renormalize interval and update streamval */
|
||||
while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */
|
||||
{
|
||||
/* read next byte from stream */
|
||||
streamval = (streamval << 8) | *++stream_ptr;
|
||||
W_upper <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
streamdata->stream_index = (int)(stream_ptr - streamdata->stream);
|
||||
streamdata->W_upper = W_upper;
|
||||
streamdata->streamval = streamval;
|
||||
|
||||
|
||||
/* find number of bytes in original stream (determined by current interval width) */
|
||||
if ( W_upper > 0x01FFFFFF )
|
||||
return streamdata->stream_index - 2;
|
||||
else
|
||||
return streamdata->stream_index - 1;
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* arith_routines.h
|
||||
*
|
||||
* This file contains functions for arithmatically encoding and
|
||||
* decoding DFT coefficients.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "arith_routines.h"
|
||||
|
||||
|
||||
|
||||
static const WebRtc_Word32 kHistEdgesQ15[51] = {
|
||||
-327680, -314573, -301466, -288359, -275252, -262144, -249037, -235930, -222823, -209716,
|
||||
-196608, -183501, -170394, -157287, -144180, -131072, -117965, -104858, -91751, -78644,
|
||||
-65536, -52429, -39322, -26215, -13108, 0, 13107, 26214, 39321, 52428,
|
||||
65536, 78643, 91750, 104857, 117964, 131072, 144179, 157286, 170393, 183500,
|
||||
196608, 209715, 222822, 235929, 249036, 262144, 275251, 288358, 301465, 314572,
|
||||
327680};
|
||||
|
||||
|
||||
static const int kCdfSlopeQ0[51] = { /* Q0 */
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 13, 23, 47, 87, 154, 315, 700, 1088,
|
||||
2471, 6064, 14221, 21463, 36634, 36924, 19750, 13270, 5806, 2312,
|
||||
1095, 660, 316, 145, 86, 41, 32, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0};
|
||||
|
||||
|
||||
static const int kCdfQ16[51] = { /* Q16 */
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
|
||||
20, 22, 24, 29, 38, 57, 92, 153, 279, 559,
|
||||
994, 1983, 4408, 10097, 18682, 33336, 48105, 56005, 61313, 63636,
|
||||
64560, 64998, 65262, 65389, 65447, 65481, 65497, 65510, 65512, 65514,
|
||||
65516, 65518, 65520, 65522, 65524, 65526, 65528, 65530, 65532, 65534,
|
||||
65535};
|
||||
|
||||
|
||||
|
||||
/* function to be converted to fixed point */
|
||||
static __inline WebRtc_UWord32 piecewise(WebRtc_Word32 xinQ15) {
|
||||
|
||||
WebRtc_Word32 ind, qtmp1, qtmp2, qtmp3;
|
||||
WebRtc_UWord32 tmpUW32;
|
||||
|
||||
|
||||
qtmp2 = xinQ15;
|
||||
|
||||
if (qtmp2 < kHistEdgesQ15[0]) {
|
||||
qtmp2 = kHistEdgesQ15[0];
|
||||
}
|
||||
if (qtmp2 > kHistEdgesQ15[50]) {
|
||||
qtmp2 = kHistEdgesQ15[50];
|
||||
}
|
||||
|
||||
qtmp1 = qtmp2 - kHistEdgesQ15[0]; /* Q15 - Q15 = Q15 */
|
||||
ind = (qtmp1 * 5) >> 16; /* 2^16 / 5 = 0.4 in Q15 */
|
||||
/* Q15 -> Q0 */
|
||||
qtmp1 = qtmp2 - kHistEdgesQ15[ind]; /* Q15 - Q15 = Q15 */
|
||||
qtmp2 = kCdfSlopeQ0[ind] * qtmp1; /* Q0 * Q15 = Q15 */
|
||||
qtmp3 = qtmp2>>15; /* Q15 -> Q0 */
|
||||
|
||||
tmpUW32 = kCdfQ16[ind] + qtmp3; /* Q0 + Q0 = Q0 */
|
||||
return tmpUW32;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int WebRtcIsac_EncLogisticMulti2(
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
WebRtc_Word16 *dataQ7, /* input: data vector */
|
||||
const WebRtc_UWord16 *envQ8, /* input: side info vector defining the width of the pdf */
|
||||
const int N, /* input: data vector length / 2 */
|
||||
const WebRtc_Word16 isSWB12kHz)
|
||||
{
|
||||
WebRtc_UWord32 W_lower, W_upper;
|
||||
WebRtc_UWord32 W_upper_LSB, W_upper_MSB;
|
||||
WebRtc_UWord8 *stream_ptr;
|
||||
WebRtc_UWord8 *maxStreamPtr;
|
||||
WebRtc_UWord8 *stream_ptr_carry;
|
||||
WebRtc_UWord32 cdf_lo, cdf_hi;
|
||||
int k;
|
||||
|
||||
/* point to beginning of stream buffer */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
W_upper = streamdata->W_upper;
|
||||
|
||||
maxStreamPtr = streamdata->stream + STREAM_SIZE_MAX_60 - 1;
|
||||
for (k = 0; k < N; k++)
|
||||
{
|
||||
/* compute cdf_lower and cdf_upper by evaluating the piecewise linear cdf */
|
||||
cdf_lo = piecewise((*dataQ7 - 64) * *envQ8);
|
||||
cdf_hi = piecewise((*dataQ7 + 64) * *envQ8);
|
||||
|
||||
/* test and clip if probability gets too small */
|
||||
while (cdf_lo+1 >= cdf_hi) {
|
||||
/* clip */
|
||||
if (*dataQ7 > 0) {
|
||||
*dataQ7 -= 128;
|
||||
cdf_hi = cdf_lo;
|
||||
cdf_lo = piecewise((*dataQ7 - 64) * *envQ8);
|
||||
} else {
|
||||
*dataQ7 += 128;
|
||||
cdf_lo = cdf_hi;
|
||||
cdf_hi = piecewise((*dataQ7 + 64) * *envQ8);
|
||||
}
|
||||
}
|
||||
|
||||
dataQ7++;
|
||||
// increment only once per 4 iterations for SWB-16kHz or WB
|
||||
// increment only once per 2 iterations for SWB-12kHz
|
||||
envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1));
|
||||
|
||||
|
||||
/* update interval */
|
||||
W_upper_LSB = W_upper & 0x0000FFFF;
|
||||
W_upper_MSB = W_upper >> 16;
|
||||
W_lower = W_upper_MSB * cdf_lo;
|
||||
W_lower += (W_upper_LSB * cdf_lo) >> 16;
|
||||
W_upper = W_upper_MSB * cdf_hi;
|
||||
W_upper += (W_upper_LSB * cdf_hi) >> 16;
|
||||
|
||||
/* shift interval such that it begins at zero */
|
||||
W_upper -= ++W_lower;
|
||||
|
||||
/* add integer to bitstream */
|
||||
streamdata->streamval += W_lower;
|
||||
|
||||
/* handle carry */
|
||||
if (streamdata->streamval < W_lower)
|
||||
{
|
||||
/* propagate carry */
|
||||
stream_ptr_carry = stream_ptr;
|
||||
while (!(++(*--stream_ptr_carry)));
|
||||
}
|
||||
|
||||
/* renormalize interval, store most significant byte of streamval and update streamval */
|
||||
while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */
|
||||
{
|
||||
W_upper <<= 8;
|
||||
*stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24);
|
||||
|
||||
if(stream_ptr > maxStreamPtr)
|
||||
{
|
||||
return -ISAC_DISALLOWED_BITSTREAM_LENGTH;
|
||||
}
|
||||
streamdata->streamval <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate new stream_index */
|
||||
streamdata->stream_index = (int)(stream_ptr - streamdata->stream);
|
||||
streamdata->W_upper = W_upper;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int WebRtcIsac_DecLogisticMulti2(
|
||||
WebRtc_Word16 *dataQ7, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const WebRtc_UWord16 *envQ8, /* input: side info vector defining the width of the pdf */
|
||||
const WebRtc_Word16 *ditherQ7,/* input: dither vector */
|
||||
const int N, /* input: data vector length */
|
||||
const WebRtc_Word16 isSWB12kHz)
|
||||
{
|
||||
WebRtc_UWord32 W_lower, W_upper;
|
||||
WebRtc_UWord32 W_tmp;
|
||||
WebRtc_UWord32 W_upper_LSB, W_upper_MSB;
|
||||
WebRtc_UWord32 streamval;
|
||||
const WebRtc_UWord8 *stream_ptr;
|
||||
WebRtc_UWord32 cdf_tmp;
|
||||
WebRtc_Word16 candQ7;
|
||||
int k;
|
||||
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
W_upper = streamdata->W_upper;
|
||||
if (streamdata->stream_index == 0) /* first time decoder is called for this stream */
|
||||
{
|
||||
/* read first word from bytestream */
|
||||
streamval = *stream_ptr << 24;
|
||||
streamval |= *++stream_ptr << 16;
|
||||
streamval |= *++stream_ptr << 8;
|
||||
streamval |= *++stream_ptr;
|
||||
} else {
|
||||
streamval = streamdata->streamval;
|
||||
}
|
||||
|
||||
|
||||
for (k = 0; k < N; k++)
|
||||
{
|
||||
/* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
|
||||
W_upper_LSB = W_upper & 0x0000FFFF;
|
||||
W_upper_MSB = W_upper >> 16;
|
||||
|
||||
/* find first candidate by inverting the logistic cdf */
|
||||
candQ7 = - *ditherQ7 + 64;
|
||||
cdf_tmp = piecewise(candQ7 * *envQ8);
|
||||
|
||||
W_tmp = W_upper_MSB * cdf_tmp;
|
||||
W_tmp += (W_upper_LSB * cdf_tmp) >> 16;
|
||||
if (streamval > W_tmp)
|
||||
{
|
||||
W_lower = W_tmp;
|
||||
candQ7 += 128;
|
||||
cdf_tmp = piecewise(candQ7 * *envQ8);
|
||||
|
||||
W_tmp = W_upper_MSB * cdf_tmp;
|
||||
W_tmp += (W_upper_LSB * cdf_tmp) >> 16;
|
||||
while (streamval > W_tmp)
|
||||
{
|
||||
W_lower = W_tmp;
|
||||
candQ7 += 128;
|
||||
cdf_tmp = piecewise(candQ7 * *envQ8);
|
||||
|
||||
W_tmp = W_upper_MSB * cdf_tmp;
|
||||
W_tmp += (W_upper_LSB * cdf_tmp) >> 16;
|
||||
|
||||
/* error check */
|
||||
if (W_lower == W_tmp) return -1;
|
||||
}
|
||||
W_upper = W_tmp;
|
||||
|
||||
/* another sample decoded */
|
||||
*dataQ7 = candQ7 - 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
W_upper = W_tmp;
|
||||
candQ7 -= 128;
|
||||
cdf_tmp = piecewise(candQ7 * *envQ8);
|
||||
|
||||
W_tmp = W_upper_MSB * cdf_tmp;
|
||||
W_tmp += (W_upper_LSB * cdf_tmp) >> 16;
|
||||
while ( !(streamval > W_tmp) )
|
||||
{
|
||||
W_upper = W_tmp;
|
||||
candQ7 -= 128;
|
||||
cdf_tmp = piecewise(candQ7 * *envQ8);
|
||||
|
||||
W_tmp = W_upper_MSB * cdf_tmp;
|
||||
W_tmp += (W_upper_LSB * cdf_tmp) >> 16;
|
||||
|
||||
/* error check */
|
||||
if (W_upper == W_tmp) return -1;
|
||||
}
|
||||
W_lower = W_tmp;
|
||||
|
||||
/* another sample decoded */
|
||||
*dataQ7 = candQ7 + 64;
|
||||
}
|
||||
ditherQ7++;
|
||||
dataQ7++;
|
||||
// increment only once per 4 iterations for SWB-16kHz or WB
|
||||
// increment only once per 2 iterations for SWB-12kHz
|
||||
envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1));
|
||||
|
||||
/* shift interval to start at zero */
|
||||
W_upper -= ++W_lower;
|
||||
|
||||
/* add integer to bitstream */
|
||||
streamval -= W_lower;
|
||||
|
||||
/* renormalize interval and update streamval */
|
||||
while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */
|
||||
{
|
||||
/* read next byte from stream */
|
||||
streamval = (streamval << 8) | *++stream_ptr;
|
||||
W_upper <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
streamdata->stream_index = (int)(stream_ptr - streamdata->stream);
|
||||
streamdata->W_upper = W_upper;
|
||||
streamdata->streamval = streamval;
|
||||
|
||||
/* find number of bytes in original stream (determined by current interval width) */
|
||||
if ( W_upper > 0x01FFFFFF )
|
||||
return streamdata->stream_index - 2;
|
||||
else
|
||||
return streamdata->stream_index - 1;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_AutoCorrToReflCoef().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_AutoCorrToReflCoef(G_CONST WebRtc_Word32 *R, int use_order, WebRtc_Word16 *K)
|
||||
{
|
||||
int i, n;
|
||||
WebRtc_Word16 tmp;
|
||||
G_CONST WebRtc_Word32 *rptr;
|
||||
WebRtc_Word32 L_num, L_den;
|
||||
WebRtc_Word16 *acfptr, *pptr, *wptr, *p1ptr, *w1ptr, ACF[WEBRTC_SPL_MAX_LPC_ORDER],
|
||||
P[WEBRTC_SPL_MAX_LPC_ORDER], W[WEBRTC_SPL_MAX_LPC_ORDER];
|
||||
|
||||
// Initialize loop and pointers.
|
||||
acfptr = ACF;
|
||||
rptr = R;
|
||||
pptr = P;
|
||||
p1ptr = &P[1];
|
||||
w1ptr = &W[1];
|
||||
wptr = w1ptr;
|
||||
|
||||
// First loop; n=0. Determine shifting.
|
||||
tmp = WebRtcSpl_NormW32(*R);
|
||||
*acfptr = (WebRtc_Word16)((*rptr++ << tmp) >> 16);
|
||||
*pptr++ = *acfptr++;
|
||||
|
||||
// Initialize ACF, P and W.
|
||||
for (i = 1; i <= use_order; i++)
|
||||
{
|
||||
*acfptr = (WebRtc_Word16)((*rptr++ << tmp) >> 16);
|
||||
*wptr++ = *acfptr;
|
||||
*pptr++ = *acfptr++;
|
||||
}
|
||||
|
||||
// Compute reflection coefficients.
|
||||
for (n = 1; n <= use_order; n++, K++)
|
||||
{
|
||||
tmp = WEBRTC_SPL_ABS_W16(*p1ptr);
|
||||
if (*P < tmp)
|
||||
{
|
||||
for (i = n; i <= use_order; i++)
|
||||
*K++ = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Division: WebRtcSpl_div(tmp, *P)
|
||||
*K = 0;
|
||||
if (tmp != 0)
|
||||
{
|
||||
L_num = tmp;
|
||||
L_den = *P;
|
||||
i = 15;
|
||||
while (i--)
|
||||
{
|
||||
(*K) <<= 1;
|
||||
L_num <<= 1;
|
||||
if (L_num >= L_den)
|
||||
{
|
||||
L_num -= L_den;
|
||||
(*K)++;
|
||||
}
|
||||
}
|
||||
if (*p1ptr > 0)
|
||||
*K = -*K;
|
||||
}
|
||||
|
||||
// Last iteration; don't do Schur recursion.
|
||||
if (n == use_order)
|
||||
return;
|
||||
|
||||
// Schur recursion.
|
||||
pptr = P;
|
||||
wptr = w1ptr;
|
||||
tmp = (WebRtc_Word16)(((WebRtc_Word32)*p1ptr * (WebRtc_Word32)*K + 16384) >> 15);
|
||||
*pptr = WEBRTC_SPL_ADD_SAT_W16( *pptr, tmp );
|
||||
pptr++;
|
||||
for (i = 1; i <= use_order - n; i++)
|
||||
{
|
||||
tmp = (WebRtc_Word16)(((WebRtc_Word32)*wptr * (WebRtc_Word32)*K + 16384) >> 15);
|
||||
*pptr = WEBRTC_SPL_ADD_SAT_W16( *(pptr+1), tmp );
|
||||
pptr++;
|
||||
tmp = (WebRtc_Word16)(((WebRtc_Word32)*pptr * (WebRtc_Word32)*K + 16384) >> 15);
|
||||
*wptr = WEBRTC_SPL_ADD_SAT_W16( *wptr, tmp );
|
||||
wptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_AutoCorrelation().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
int WebRtcSpl_AutoCorrelation(G_CONST WebRtc_Word16* in_vector,
|
||||
int in_vector_length,
|
||||
int order,
|
||||
WebRtc_Word32* result,
|
||||
int* scale)
|
||||
{
|
||||
WebRtc_Word32 sum;
|
||||
int i, j;
|
||||
WebRtc_Word16 smax; // Sample max
|
||||
G_CONST WebRtc_Word16* xptr1;
|
||||
G_CONST WebRtc_Word16* xptr2;
|
||||
WebRtc_Word32* resultptr;
|
||||
int scaling = 0;
|
||||
|
||||
#ifdef _ARM_OPT_
|
||||
#pragma message("NOTE: _ARM_OPT_ optimizations are used")
|
||||
WebRtc_Word16 loops4;
|
||||
#endif
|
||||
|
||||
if (order < 0)
|
||||
order = in_vector_length;
|
||||
|
||||
// Find the max. sample
|
||||
smax = WebRtcSpl_MaxAbsValueW16(in_vector, in_vector_length);
|
||||
|
||||
// In order to avoid overflow when computing the sum we should scale the samples so that
|
||||
// (in_vector_length * smax * smax) will not overflow.
|
||||
|
||||
if (smax == 0)
|
||||
{
|
||||
scaling = 0;
|
||||
} else
|
||||
{
|
||||
int nbits = WebRtcSpl_GetSizeInBits(in_vector_length); // # of bits in the sum loop
|
||||
int t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax)); // # of bits to normalize smax
|
||||
|
||||
if (t > nbits)
|
||||
{
|
||||
scaling = 0;
|
||||
} else
|
||||
{
|
||||
scaling = nbits - t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
resultptr = result;
|
||||
|
||||
// Perform the actual correlation calculation
|
||||
for (i = 0; i < order + 1; i++)
|
||||
{
|
||||
int loops = (in_vector_length - i);
|
||||
sum = 0;
|
||||
xptr1 = in_vector;
|
||||
xptr2 = &in_vector[i];
|
||||
#ifndef _ARM_OPT_
|
||||
for (j = loops; j > 0; j--)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1++, *xptr2++, scaling);
|
||||
}
|
||||
#else
|
||||
loops4 = (loops >> 2) << 2;
|
||||
|
||||
if (scaling == 0)
|
||||
{
|
||||
for (j = 0; j < loops4; j = j + 4)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
}
|
||||
|
||||
for (j = loops4; j < loops; j++)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; j < loops4; j = j + 4)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
}
|
||||
|
||||
for (j = loops4; j < loops; j++)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling);
|
||||
xptr1++;
|
||||
xptr2++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
*resultptr++ = sum;
|
||||
}
|
||||
|
||||
*scale = scaling;
|
||||
|
||||
return order + 1;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* bandwidth_estimator.h
|
||||
*
|
||||
* This header file contains the API for the Bandwidth Estimator
|
||||
* designed for iSAC.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
|
||||
|
||||
#include "structs.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
#define MIN_ISAC_BW 10000
|
||||
#define MIN_ISAC_BW_LB 10000
|
||||
#define MIN_ISAC_BW_UB 25000
|
||||
|
||||
#define MAX_ISAC_BW 56000
|
||||
#define MAX_ISAC_BW_UB 32000
|
||||
#define MAX_ISAC_BW_LB 32000
|
||||
|
||||
#define MIN_ISAC_MD 5
|
||||
#define MAX_ISAC_MD 25
|
||||
|
||||
// assumed header size, in bytes; we don't know the exact number
|
||||
// (header compression may be used)
|
||||
#define HEADER_SIZE 35
|
||||
|
||||
// Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode
|
||||
#define INIT_FRAME_LEN_WB 60
|
||||
#define INIT_FRAME_LEN_SWB 30
|
||||
|
||||
// Initial Bottleneck Estimate, in bits/sec, for
|
||||
// Wideband & Super-wideband mode
|
||||
#define INIT_BN_EST_WB 20e3f
|
||||
#define INIT_BN_EST_SWB 56e3f
|
||||
|
||||
// Initial Header rate (header rate depends on frame-size),
|
||||
// in bits/sec, for Wideband & Super-Wideband mode.
|
||||
#define INIT_HDR_RATE_WB \
|
||||
((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB)
|
||||
#define INIT_HDR_RATE_SWB \
|
||||
((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB)
|
||||
|
||||
// number of packets in a row for a high rate burst
|
||||
#define BURST_LEN 3
|
||||
|
||||
// ms, max time between two full bursts
|
||||
#define BURST_INTERVAL 500
|
||||
|
||||
// number of packets in a row for initial high rate burst
|
||||
#define INIT_BURST_LEN 5
|
||||
|
||||
// bits/s, rate for the first BURST_LEN packets
|
||||
#define INIT_RATE_WB INIT_BN_EST_WB
|
||||
#define INIT_RATE_SWB INIT_BN_EST_SWB
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This function initializes the struct */
|
||||
/* to be called before using the struct for anything else */
|
||||
/* returns 0 if everything went fine, -1 otherwise */
|
||||
WebRtc_Word32 WebRtcIsac_InitBandwidthEstimator(
|
||||
BwEstimatorstr* bwest_str,
|
||||
enum IsacSamplingRate encoderSampRate,
|
||||
enum IsacSamplingRate decoderSampRate);
|
||||
|
||||
/* This function updates the receiving estimate */
|
||||
/* Parameters: */
|
||||
/* rtp_number - value from RTP packet, from NetEq */
|
||||
/* frame length - length of signal frame in ms, from iSAC decoder */
|
||||
/* send_ts - value in RTP header giving send time in samples */
|
||||
/* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */
|
||||
/* pksize - size of packet in bytes, from NetEq */
|
||||
/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
|
||||
/* returns 0 if everything went fine, -1 otherwise */
|
||||
WebRtc_Word16 WebRtcIsac_UpdateBandwidthEstimator(
|
||||
BwEstimatorstr* bwest_str,
|
||||
const WebRtc_UWord16 rtp_number,
|
||||
const WebRtc_Word32 frame_length,
|
||||
const WebRtc_UWord32 send_ts,
|
||||
const WebRtc_UWord32 arr_ts,
|
||||
const WebRtc_Word32 pksize);
|
||||
|
||||
/* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */
|
||||
WebRtc_Word16 WebRtcIsac_UpdateUplinkBwImpl(
|
||||
BwEstimatorstr* bwest_str,
|
||||
WebRtc_Word16 Index,
|
||||
enum IsacSamplingRate encoderSamplingFreq);
|
||||
|
||||
/* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the sending iSAC payload */
|
||||
WebRtc_UWord16 WebRtcIsac_GetDownlinkBwJitIndexImpl(
|
||||
BwEstimatorstr* bwest_str,
|
||||
WebRtc_Word16* bottleneckIndex,
|
||||
WebRtc_Word16* jitterInfo,
|
||||
enum IsacSamplingRate decoderSamplingFreq);
|
||||
|
||||
/* Returns the bandwidth estimation (in bps) */
|
||||
WebRtc_Word32 WebRtcIsac_GetDownlinkBandwidth(
|
||||
const BwEstimatorstr *bwest_str);
|
||||
|
||||
/* Returns the max delay (in ms) */
|
||||
WebRtc_Word32 WebRtcIsac_GetDownlinkMaxDelay(
|
||||
const BwEstimatorstr *bwest_str);
|
||||
|
||||
/* Returns the bandwidth that iSAC should send with in bps */
|
||||
void WebRtcIsac_GetUplinkBandwidth(
|
||||
const BwEstimatorstr* bwest_str,
|
||||
WebRtc_Word32* bitRate);
|
||||
|
||||
/* Returns the max delay value from the other side in ms */
|
||||
WebRtc_Word32 WebRtcIsac_GetUplinkMaxDelay(
|
||||
const BwEstimatorstr *bwest_str);
|
||||
|
||||
|
||||
/*
|
||||
* update amount of data in bottle neck buffer and burst handling
|
||||
* returns minimum payload size (bytes)
|
||||
*/
|
||||
int WebRtcIsac_GetMinBytes(
|
||||
RateModel* State,
|
||||
int StreamSize, /* bytes in bitstream */
|
||||
const int FrameLen, /* ms per frame */
|
||||
const double BottleNeck, /* bottle neck rate; excl headers (bps) */
|
||||
const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
|
||||
enum ISACBandwidth bandwidth
|
||||
/*,WebRtc_Word16 frequentLargePackets*/);
|
||||
|
||||
/*
|
||||
* update long-term average bitrate and amount of data in buffer
|
||||
*/
|
||||
void WebRtcIsac_UpdateRateModel(
|
||||
RateModel* State,
|
||||
int StreamSize, /* bytes in bitstream */
|
||||
const int FrameSamples, /* samples per frame */
|
||||
const double BottleNeck); /* bottle neck rate; excl headers (bps) */
|
||||
|
||||
|
||||
void WebRtcIsac_InitRateModel(
|
||||
RateModel *State);
|
||||
|
||||
/* Returns the new framelength value (input argument: bottle_neck) */
|
||||
int WebRtcIsac_GetNewFrameLength(
|
||||
double bottle_neck,
|
||||
int current_framelength);
|
||||
|
||||
/* Returns the new SNR value (input argument: bottle_neck) */
|
||||
double WebRtcIsac_GetSnr(
|
||||
double bottle_neck,
|
||||
int new_framelength);
|
||||
|
||||
|
||||
WebRtc_Word16 WebRtcIsac_UpdateUplinkJitter(
|
||||
BwEstimatorstr* bwest_str,
|
||||
WebRtc_Word32 index);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ */
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* codec.h
|
||||
*
|
||||
* This header file contains the calls to the internal encoder
|
||||
* and decoder functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
int WebRtcIsac_EstimateBandwidth(
|
||||
BwEstimatorstr* bwest_str,
|
||||
Bitstr* streamdata,
|
||||
WebRtc_Word32 packet_size,
|
||||
WebRtc_UWord16 rtp_seq_number,
|
||||
WebRtc_UWord32 send_ts,
|
||||
WebRtc_UWord32 arr_ts,
|
||||
enum IsacSamplingRate encoderSampRate,
|
||||
enum IsacSamplingRate decoderSampRate);
|
||||
|
||||
int WebRtcIsac_DecodeLb(
|
||||
float* signal_out,
|
||||
ISACLBDecStruct* ISACdec_obj,
|
||||
WebRtc_Word16* current_framesamples,
|
||||
WebRtc_Word16 isRCUPayload);
|
||||
|
||||
int WebRtcIsac_DecodeRcuLb(
|
||||
float* signal_out,
|
||||
ISACLBDecStruct* ISACdec_obj,
|
||||
WebRtc_Word16* current_framesamples);
|
||||
|
||||
int WebRtcIsac_EncodeLb(
|
||||
float* in,
|
||||
ISACLBEncStruct* ISACencLB_obj,
|
||||
WebRtc_Word16 codingMode,
|
||||
WebRtc_Word16 bottleneckIndex);
|
||||
|
||||
int WebRtcIsac_EncodeStoredDataLb(
|
||||
const ISAC_SaveEncData_t* ISACSavedEnc_obj,
|
||||
Bitstr* ISACBitStr_obj,
|
||||
int BWnumber,
|
||||
float scale);
|
||||
|
||||
|
||||
int WebRtcIsac_EncodeStoredDataUb12(
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
|
||||
Bitstr* bitStream,
|
||||
WebRtc_Word32 jitterInfo,
|
||||
float scale);
|
||||
|
||||
int WebRtcIsac_EncodeStoredDataUb16(
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
|
||||
Bitstr* bitStream,
|
||||
WebRtc_Word32 jitterInfo,
|
||||
float scale);
|
||||
|
||||
|
||||
WebRtc_Word16 WebRtcIsac_GetRedPayloadUb(
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEncObj,
|
||||
Bitstr* bitStreamObj,
|
||||
enum ISACBandwidth bandwidth);
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RateAllocation()
|
||||
* Internal function to perform a rate-allocation for upper and lower-band,
|
||||
* given a total rate.
|
||||
*
|
||||
* Input:
|
||||
* - inRateBitPerSec : a total bit-rate in bits/sec.
|
||||
*
|
||||
* Output:
|
||||
* - rateLBBitPerSec : a bit-rate allocated to the lower-band
|
||||
* in bits/sec.
|
||||
* - rateUBBitPerSec : a bit-rate allocated to the upper-band
|
||||
* in bits/sec.
|
||||
*
|
||||
* Return value : 0 if rate allocation has been successful.
|
||||
* -1 if failed to allocate rates.
|
||||
*/
|
||||
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_RateAllocation(
|
||||
WebRtc_Word32 inRateBitPerSec,
|
||||
double* rateLBBitPerSec,
|
||||
double* rateUBBitPerSec,
|
||||
enum ISACBandwidth* bandwidthKHz);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeUb16()
|
||||
*
|
||||
* Decode the upper-band if the codec is in 0-16 kHz mode.
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band decoder object. The
|
||||
* bit-stream is stored inside the decoder object.
|
||||
*
|
||||
* Output:
|
||||
* -signal_out : decoded audio, 480 samples 30 ms.
|
||||
*
|
||||
* Return value : >0 number of decoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_DecodeUb16(
|
||||
float* signal_out,
|
||||
ISACUBDecStruct* ISACdec_obj,
|
||||
WebRtc_Word16 isRCUPayload);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeUb12()
|
||||
*
|
||||
* Decode the upper-band if the codec is in 0-12 kHz mode.
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band decoder object. The
|
||||
* bit-stream is stored inside the decoder object.
|
||||
*
|
||||
* Output:
|
||||
* -signal_out : decoded audio, 480 samples 30 ms.
|
||||
*
|
||||
* Return value : >0 number of decoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_DecodeUb12(
|
||||
float* signal_out,
|
||||
ISACUBDecStruct* ISACdec_obj,
|
||||
WebRtc_Word16 isRCUPayload);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeUb16()
|
||||
*
|
||||
* Encode the upper-band if the codec is in 0-16 kHz mode.
|
||||
*
|
||||
* Input:
|
||||
* -in : upper-band audio, 160 samples (10 ms).
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band encoder object. The
|
||||
* bit-stream is stored inside the encoder object.
|
||||
*
|
||||
* Return value : >0 number of encoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_EncodeUb16(
|
||||
float* in,
|
||||
ISACUBEncStruct* ISACenc_obj,
|
||||
WebRtc_Word32 jitterInfo);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeUb12()
|
||||
*
|
||||
* Encode the upper-band if the codec is in 0-12 kHz mode.
|
||||
*
|
||||
* Input:
|
||||
* -in : upper-band audio, 160 samples (10 ms).
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band encoder object. The
|
||||
* bit-stream is stored inside the encoder object.
|
||||
*
|
||||
* Return value : >0 number of encoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_EncodeUb12(
|
||||
float* in,
|
||||
ISACUBEncStruct* ISACenc_obj,
|
||||
WebRtc_Word32 jitterInfo);
|
||||
|
||||
/************************** initialization functions *************************/
|
||||
|
||||
void WebRtcIsac_InitMasking(MaskFiltstr *maskdata);
|
||||
|
||||
void WebRtcIsac_InitPreFilterbank(PreFiltBankstr *prefiltdata);
|
||||
|
||||
void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata);
|
||||
|
||||
void WebRtcIsac_InitPitchFilter(PitchFiltstr *pitchfiltdata);
|
||||
|
||||
void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct *State);
|
||||
|
||||
|
||||
/**************************** transform functions ****************************/
|
||||
|
||||
void WebRtcIsac_InitTransform();
|
||||
|
||||
void WebRtcIsac_Time2Spec(double *inre1,
|
||||
double *inre2,
|
||||
WebRtc_Word16 *outre,
|
||||
WebRtc_Word16 *outim,
|
||||
FFTstr *fftstr_obj);
|
||||
|
||||
void WebRtcIsac_Spec2time(double *inre,
|
||||
double *inim,
|
||||
double *outre1,
|
||||
double *outre2,
|
||||
FFTstr *fftstr_obj);
|
||||
|
||||
|
||||
/******************************* filter functions ****************************/
|
||||
|
||||
void WebRtcIsac_AllPoleFilter(double *InOut,
|
||||
double *Coef,
|
||||
int lengthInOut,
|
||||
int orderCoef);
|
||||
|
||||
void WebRtcIsac_AllZeroFilter(double *In,
|
||||
double *Coef,
|
||||
int lengthInOut,
|
||||
int orderCoef,
|
||||
double *Out);
|
||||
|
||||
void WebRtcIsac_ZeroPoleFilter(double *In,
|
||||
double *ZeroCoef,
|
||||
double *PoleCoef,
|
||||
int lengthInOut,
|
||||
int orderCoef,
|
||||
double *Out);
|
||||
|
||||
|
||||
/***************************** filterbank functions **************************/
|
||||
|
||||
void WebRtcIsac_SplitAndFilter(double *in,
|
||||
double *LP,
|
||||
double *HP,
|
||||
double *LP_la,
|
||||
double *HP_la,
|
||||
PreFiltBankstr *prefiltdata);
|
||||
|
||||
|
||||
void WebRtcIsac_FilterAndCombine(double *InLP,
|
||||
double *InHP,
|
||||
double *Out,
|
||||
PostFiltBankstr *postfiltdata);
|
||||
|
||||
|
||||
|
||||
void WebRtcIsac_SplitAndFilterFloat(float *in,
|
||||
float *LP,
|
||||
float *HP,
|
||||
double *LP_la,
|
||||
double *HP_la,
|
||||
PreFiltBankstr *prefiltdata);
|
||||
|
||||
|
||||
void WebRtcIsac_FilterAndCombineFloat(float *InLP,
|
||||
float *InHP,
|
||||
float *Out,
|
||||
PostFiltBankstr *postfiltdata);
|
||||
|
||||
|
||||
/************************* normalized lattice filters ************************/
|
||||
|
||||
void WebRtcIsac_NormLatticeFilterMa(int orderCoef,
|
||||
float *stateF,
|
||||
float *stateG,
|
||||
float *lat_in,
|
||||
double *filtcoeflo,
|
||||
double *lat_out);
|
||||
|
||||
void WebRtcIsac_NormLatticeFilterAr(int orderCoef,
|
||||
float *stateF,
|
||||
float *stateG,
|
||||
double *lat_in,
|
||||
double *lo_filt_coef,
|
||||
float *lat_out);
|
||||
|
||||
void WebRtcIsac_Dir2Lat(double *a,
|
||||
int orderCoef,
|
||||
float *sth,
|
||||
float *cth);
|
||||
|
||||
void WebRtcIsac_AutoCorr(double *r,
|
||||
const double *x,
|
||||
int N,
|
||||
int order);
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_ComplexBitReverse().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_ComplexBitReverse(WebRtc_Word16 frfi[], int stages)
|
||||
{
|
||||
int mr, nn, n, l, m;
|
||||
WebRtc_Word16 tr, ti;
|
||||
|
||||
n = 1 << stages;
|
||||
|
||||
mr = 0;
|
||||
nn = n - 1;
|
||||
|
||||
// decimation in time - re-order data
|
||||
for (m = 1; m <= nn; ++m)
|
||||
{
|
||||
l = n;
|
||||
do
|
||||
{
|
||||
l >>= 1;
|
||||
} while (mr + l > nn);
|
||||
mr = (mr & (l - 1)) + l;
|
||||
|
||||
if (mr <= m)
|
||||
continue;
|
||||
|
||||
tr = frfi[2 * m];
|
||||
frfi[2 * m] = frfi[2 * mr];
|
||||
frfi[2 * mr] = tr;
|
||||
|
||||
ti = frfi[2 * m + 1];
|
||||
frfi[2 * m + 1] = frfi[2 * mr + 1];
|
||||
frfi[2 * mr + 1] = ti;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_ComplexFFT().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#define CFFTSFT 14
|
||||
#define CFFTRND 1
|
||||
#define CFFTRND2 16384
|
||||
|
||||
#define CIFFTSFT 14
|
||||
#define CIFFTRND 1
|
||||
|
||||
static const WebRtc_Word16 kSinTable1024[] = {
|
||||
0, 201, 402, 603, 804, 1005, 1206, 1406,
|
||||
1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
|
||||
3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608,
|
||||
4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195,
|
||||
6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766,
|
||||
7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319,
|
||||
9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849,
|
||||
11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353,
|
||||
12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827,
|
||||
14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268,
|
||||
15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672,
|
||||
16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036,
|
||||
18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357,
|
||||
19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631,
|
||||
20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855,
|
||||
22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027,
|
||||
23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143,
|
||||
24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
|
||||
25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198,
|
||||
26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132,
|
||||
27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001,
|
||||
28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802,
|
||||
28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534,
|
||||
29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195,
|
||||
30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783,
|
||||
30851, 30918, 30984, 31049,
|
||||
31113, 31175, 31236, 31297,
|
||||
31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735,
|
||||
31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097,
|
||||
32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382,
|
||||
32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588,
|
||||
32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717,
|
||||
32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766,
|
||||
32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736,
|
||||
32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628,
|
||||
32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441,
|
||||
32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
|
||||
32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833,
|
||||
31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413,
|
||||
31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918,
|
||||
30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349,
|
||||
30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706,
|
||||
29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992,
|
||||
28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208,
|
||||
28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355,
|
||||
27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437,
|
||||
26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456,
|
||||
25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413,
|
||||
24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311,
|
||||
23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153,
|
||||
22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942,
|
||||
20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680,
|
||||
19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371,
|
||||
18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017,
|
||||
16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
|
||||
15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191,
|
||||
14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724,
|
||||
12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227,
|
||||
11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703,
|
||||
9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156,
|
||||
7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589,
|
||||
6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006,
|
||||
4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411,
|
||||
3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808,
|
||||
1607, 1406, 1206, 1005, 804, 603, 402, 201,
|
||||
0, -201, -402, -603, -804, -1005, -1206, -1406,
|
||||
-1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011,
|
||||
-3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608,
|
||||
-4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195,
|
||||
-6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766,
|
||||
-7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319,
|
||||
-9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849,
|
||||
-11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
|
||||
-12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
|
||||
-14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
|
||||
-15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
|
||||
-16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
|
||||
-18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
|
||||
-19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
|
||||
-20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
|
||||
-22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
|
||||
-23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
|
||||
-24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
|
||||
-25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
|
||||
-26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
|
||||
-27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
|
||||
-28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
|
||||
-28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
|
||||
-29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
|
||||
-30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
|
||||
-30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
|
||||
-31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
|
||||
-31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
|
||||
-32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
|
||||
-32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
|
||||
-32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
|
||||
-32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
|
||||
-32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
|
||||
-32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
|
||||
-32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
|
||||
-32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
|
||||
-32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
|
||||
-31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
|
||||
-31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
|
||||
-30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
|
||||
-30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
|
||||
-29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
|
||||
-28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
|
||||
-28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
|
||||
-27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
|
||||
-26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
|
||||
-25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
|
||||
-24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
|
||||
-23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
|
||||
-22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
|
||||
-20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
|
||||
-19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
|
||||
-18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
|
||||
-16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
|
||||
-15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
|
||||
-14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
|
||||
-12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
|
||||
-11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703,
|
||||
-9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156,
|
||||
-7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589,
|
||||
-6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006,
|
||||
-4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
|
||||
-3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808,
|
||||
-1607, -1406, -1206, -1005, -804, -603, -402, -201
|
||||
};
|
||||
|
||||
int WebRtcSpl_ComplexFFT(WebRtc_Word16 frfi[], int stages, int mode)
|
||||
{
|
||||
int i, j, l, k, istep, n, m;
|
||||
WebRtc_Word16 wr, wi;
|
||||
WebRtc_Word32 tr32, ti32, qr32, qi32;
|
||||
|
||||
/* The 1024-value is a constant given from the size of kSinTable1024[],
|
||||
* and should not be changed depending on the input parameter 'stages'
|
||||
*/
|
||||
n = 1 << stages;
|
||||
if (n > 1024)
|
||||
return -1;
|
||||
|
||||
l = 1;
|
||||
k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
|
||||
depending on the input parameter 'stages' */
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
// mode==0: Low-complexity and Low-accuracy mode
|
||||
while (l < n)
|
||||
{
|
||||
istep = l << 1;
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = -kSinTable1024[j];
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
|
||||
- WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1])), 15);
|
||||
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
|
||||
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j])), 15);
|
||||
|
||||
qr32 = (WebRtc_Word32)frfi[2 * i];
|
||||
qi32 = (WebRtc_Word32)frfi[2 * i + 1];
|
||||
frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, 1);
|
||||
frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, 1);
|
||||
frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, 1);
|
||||
frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, 1);
|
||||
}
|
||||
}
|
||||
|
||||
--k;
|
||||
l = istep;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
// mode==1: High-complexity and High-accuracy mode
|
||||
while (l < n)
|
||||
{
|
||||
istep = l << 1;
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = -kSinTable1024[j];
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7A
|
||||
WebRtc_Word32 wri;
|
||||
WebRtc_Word32 frfi_r;
|
||||
__asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
|
||||
"r"((WebRtc_Word32)wr), "r"((WebRtc_Word32)wi));
|
||||
#endif
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7A
|
||||
__asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(frfi_r) :
|
||||
"r"((WebRtc_Word32)frfi[2*j]), "r"((WebRtc_Word32)frfi[2*j +1]));
|
||||
__asm__("smlsd %0, %1, %2, %3" : "=r"(tr32) :
|
||||
"r"(wri), "r"(frfi_r), "r"(CFFTRND));
|
||||
__asm__("smladx %0, %1, %2, %3" : "=r"(ti32) :
|
||||
"r"(wri), "r"(frfi_r), "r"(CFFTRND));
|
||||
|
||||
#else
|
||||
tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
|
||||
- WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CFFTRND;
|
||||
|
||||
ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
|
||||
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND;
|
||||
#endif
|
||||
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CFFTSFT);
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CFFTSFT);
|
||||
|
||||
qr32 = ((WebRtc_Word32)frfi[2 * i]) << CFFTSFT;
|
||||
qi32 = ((WebRtc_Word32)frfi[2 * i + 1]) << CFFTSFT;
|
||||
|
||||
frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qr32 - tr32 + CFFTRND2), 1 + CFFTSFT);
|
||||
frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 - ti32 + CFFTRND2), 1 + CFFTSFT);
|
||||
frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qr32 + tr32 + CFFTRND2), 1 + CFFTSFT);
|
||||
frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 + ti32 + CFFTRND2), 1 + CFFTSFT);
|
||||
}
|
||||
}
|
||||
|
||||
--k;
|
||||
l = istep;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcSpl_ComplexIFFT(WebRtc_Word16 frfi[], int stages, int mode)
|
||||
{
|
||||
int i, j, l, k, istep, n, m, scale, shift;
|
||||
WebRtc_Word16 wr, wi;
|
||||
WebRtc_Word32 tr32, ti32, qr32, qi32;
|
||||
WebRtc_Word32 tmp32, round2;
|
||||
|
||||
/* The 1024-value is a constant given from the size of kSinTable1024[],
|
||||
* and should not be changed depending on the input parameter 'stages'
|
||||
*/
|
||||
n = 1 << stages;
|
||||
if (n > 1024)
|
||||
return -1;
|
||||
|
||||
scale = 0;
|
||||
|
||||
l = 1;
|
||||
k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
|
||||
depending on the input parameter 'stages' */
|
||||
|
||||
while (l < n)
|
||||
{
|
||||
// variable scaling, depending upon data
|
||||
shift = 0;
|
||||
round2 = 8192;
|
||||
|
||||
tmp32 = (WebRtc_Word32)WebRtcSpl_MaxAbsValueW16(frfi, 2 * n);
|
||||
if (tmp32 > 13573)
|
||||
{
|
||||
shift++;
|
||||
scale++;
|
||||
round2 <<= 1;
|
||||
}
|
||||
if (tmp32 > 27146)
|
||||
{
|
||||
shift++;
|
||||
scale++;
|
||||
round2 <<= 1;
|
||||
}
|
||||
|
||||
istep = l << 1;
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
// mode==0: Low-complexity and Low-accuracy mode
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = kSinTable1024[j];
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0)
|
||||
- WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15);
|
||||
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32(
|
||||
(WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0)
|
||||
+ WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15);
|
||||
|
||||
qr32 = (WebRtc_Word32)frfi[2 * i];
|
||||
qi32 = (WebRtc_Word32)frfi[2 * i + 1];
|
||||
frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift);
|
||||
frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift);
|
||||
frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift);
|
||||
frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift);
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
// mode==1: High-complexity and High-accuracy mode
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = kSinTable1024[j];
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7A
|
||||
WebRtc_Word32 wri;
|
||||
WebRtc_Word32 frfi_r;
|
||||
__asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
|
||||
"r"((WebRtc_Word32)wr), "r"((WebRtc_Word32)wi));
|
||||
#endif
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7A
|
||||
__asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(frfi_r) :
|
||||
"r"((WebRtc_Word32)frfi[2*j]), "r"((WebRtc_Word32)frfi[2*j +1]));
|
||||
__asm__("smlsd %0, %1, %2, %3" : "=r"(tr32) :
|
||||
"r"(wri), "r"(frfi_r), "r"(CIFFTRND));
|
||||
__asm__("smladx %0, %1, %2, %3" : "=r"(ti32) :
|
||||
"r"(wri), "r"(frfi_r), "r"(CIFFTRND));
|
||||
#else
|
||||
|
||||
tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
|
||||
- WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CIFFTRND;
|
||||
|
||||
ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
|
||||
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CIFFTRND;
|
||||
#endif
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CIFFTSFT);
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CIFFTSFT);
|
||||
|
||||
qr32 = ((WebRtc_Word32)frfi[2 * i]) << CIFFTSFT;
|
||||
qi32 = ((WebRtc_Word32)frfi[2 * i + 1]) << CIFFTSFT;
|
||||
|
||||
frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2),
|
||||
shift+CIFFTSFT);
|
||||
frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 - ti32 + round2), shift + CIFFTSFT);
|
||||
frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2),
|
||||
shift + CIFFTSFT);
|
||||
frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 + ti32 + round2), shift + CIFFTSFT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
--k;
|
||||
l = istep;
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the implementation of functions
|
||||
* WebRtcSpl_MemSetW16()
|
||||
* WebRtcSpl_MemSetW32()
|
||||
* WebRtcSpl_MemCpyReversedOrder()
|
||||
* WebRtcSpl_CopyFromEndW16()
|
||||
* WebRtcSpl_ZerosArrayW16()
|
||||
* WebRtcSpl_ZerosArrayW32()
|
||||
* WebRtcSpl_OnesArrayW16()
|
||||
* WebRtcSpl_OnesArrayW32()
|
||||
*
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
|
||||
void WebRtcSpl_MemSetW16(WebRtc_Word16 *ptr, WebRtc_Word16 set_value, int length)
|
||||
{
|
||||
int j;
|
||||
WebRtc_Word16 *arrptr = ptr;
|
||||
|
||||
for (j = length; j > 0; j--)
|
||||
{
|
||||
*arrptr++ = set_value;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_MemSetW32(WebRtc_Word32 *ptr, WebRtc_Word32 set_value, int length)
|
||||
{
|
||||
int j;
|
||||
WebRtc_Word32 *arrptr = ptr;
|
||||
|
||||
for (j = length; j > 0; j--)
|
||||
{
|
||||
*arrptr++ = set_value;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_MemCpyReversedOrder(WebRtc_Word16* dest, WebRtc_Word16* source, int length)
|
||||
{
|
||||
int j;
|
||||
WebRtc_Word16* destPtr = dest;
|
||||
WebRtc_Word16* sourcePtr = source;
|
||||
|
||||
for (j = 0; j < length; j++)
|
||||
{
|
||||
*destPtr-- = *sourcePtr++;
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word16 WebRtcSpl_CopyFromEndW16(G_CONST WebRtc_Word16 *vector_in,
|
||||
WebRtc_Word16 length,
|
||||
WebRtc_Word16 samples,
|
||||
WebRtc_Word16 *vector_out)
|
||||
{
|
||||
// Copy the last <samples> of the input vector to vector_out
|
||||
WEBRTC_SPL_MEMCPY_W16(vector_out, &vector_in[length - samples], samples);
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
WebRtc_Word16 WebRtcSpl_ZerosArrayW16(WebRtc_Word16 *vector, WebRtc_Word16 length)
|
||||
{
|
||||
WebRtcSpl_MemSetW16(vector, 0, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
WebRtc_Word16 WebRtcSpl_ZerosArrayW32(WebRtc_Word32 *vector, WebRtc_Word16 length)
|
||||
{
|
||||
WebRtcSpl_MemSetW32(vector, 0, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
WebRtc_Word16 WebRtcSpl_OnesArrayW16(WebRtc_Word16 *vector, WebRtc_Word16 length)
|
||||
{
|
||||
WebRtc_Word16 i;
|
||||
WebRtc_Word16 *tmpvec = vector;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
*tmpvec++ = 1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
WebRtc_Word16 WebRtcSpl_OnesArrayW32(WebRtc_Word32 *vector, WebRtc_Word16 length)
|
||||
{
|
||||
WebRtc_Word16 i;
|
||||
WebRtc_Word32 *tmpvec = vector;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
*tmpvec++ = 1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "crc.h"
|
||||
#include <stdlib.h>
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#define POLYNOMIAL 0x04c11db7L
|
||||
|
||||
|
||||
static const WebRtc_UWord32 kCrcTable[256] = {
|
||||
0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b,
|
||||
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
|
||||
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
|
||||
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
|
||||
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
|
||||
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
|
||||
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4,
|
||||
0x808d07d, 0xcc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
|
||||
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
|
||||
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
|
||||
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
|
||||
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
|
||||
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
|
||||
0x3f9b762c, 0x3b5a6b9b, 0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff,
|
||||
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
|
||||
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
|
||||
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
|
||||
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
|
||||
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
|
||||
0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
|
||||
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
|
||||
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
|
||||
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_GetCrc(...)
|
||||
*
|
||||
* This function returns a 32 bit CRC checksum of a bit stream
|
||||
*
|
||||
* Input:
|
||||
* - bitstream : payload bitstream
|
||||
* - len_bitstream_in_bytes : number of 8-bit words in the bit stream
|
||||
*
|
||||
* Output:
|
||||
* - crc : checksum
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
WebRtc_Word16 WebRtcIsac_GetCrc(const WebRtc_Word16* bitstream,
|
||||
WebRtc_Word16 len_bitstream_in_bytes,
|
||||
WebRtc_UWord32* crc)
|
||||
{
|
||||
WebRtc_UWord8* bitstream_ptr_uw8;
|
||||
WebRtc_UWord32 crc_state;
|
||||
int byte_cntr;
|
||||
int crc_tbl_indx;
|
||||
|
||||
/* Sanity Check. */
|
||||
if (bitstream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* cast to UWord8 pointer */
|
||||
bitstream_ptr_uw8 = (WebRtc_UWord8 *)bitstream;
|
||||
|
||||
/* initialize */
|
||||
crc_state = 0xFFFFFFFF;
|
||||
|
||||
for (byte_cntr = 0; byte_cntr < len_bitstream_in_bytes; byte_cntr++) {
|
||||
crc_tbl_indx = (WEBRTC_SPL_RSHIFT_U32(crc_state, 24) ^
|
||||
bitstream_ptr_uw8[byte_cntr]) & 0xFF;
|
||||
crc_state = WEBRTC_SPL_LSHIFT_U32(crc_state, 8) ^ kCrcTable[crc_tbl_indx];
|
||||
}
|
||||
|
||||
*crc = ~crc_state;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* crc.h
|
||||
*
|
||||
* Checksum functions
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_GetCrc(...)
|
||||
*
|
||||
* This function returns a 32 bit CRC checksum of a bit stream
|
||||
*
|
||||
* Input:
|
||||
* - encoded : payload bit stream
|
||||
* - no_of_word8s : number of 8-bit words in the bit stream
|
||||
*
|
||||
* Output:
|
||||
* - crc : checksum
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
WebRtc_Word16 WebRtcIsac_GetCrc(
|
||||
const WebRtc_Word16* encoded,
|
||||
WebRtc_Word16 no_of_word8s,
|
||||
WebRtc_UWord32* crc);
|
||||
|
||||
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_CrossCorrelation().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
/* TODO(kma): Clean up the code in this file, and break it up for
|
||||
* various platforms (Xscale, ARM/Neon etc.).
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_CrossCorrelation(WebRtc_Word32* cross_correlation, WebRtc_Word16* seq1,
|
||||
WebRtc_Word16* seq2, WebRtc_Word16 dim_seq,
|
||||
WebRtc_Word16 dim_cross_correlation,
|
||||
WebRtc_Word16 right_shifts,
|
||||
WebRtc_Word16 step_seq2)
|
||||
{
|
||||
int i, j;
|
||||
WebRtc_Word16* seq1Ptr;
|
||||
WebRtc_Word16* seq2Ptr;
|
||||
WebRtc_Word32* CrossCorrPtr;
|
||||
|
||||
#ifdef _XSCALE_OPT_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma message("NOTE: _XSCALE_OPT_ optimizations are used (overrides _ARM_OPT_ and requires /QRxscale compiler flag)")
|
||||
#endif
|
||||
|
||||
__int64 macc40;
|
||||
|
||||
int iseq1[250];
|
||||
int iseq2[250];
|
||||
int iseq3[250];
|
||||
int * iseq1Ptr;
|
||||
int * iseq2Ptr;
|
||||
int * iseq3Ptr;
|
||||
int len, i_len;
|
||||
|
||||
seq1Ptr = seq1;
|
||||
iseq1Ptr = iseq1;
|
||||
for(i = 0; i < ((dim_seq + 1) >> 1); i++)
|
||||
{
|
||||
*iseq1Ptr = (unsigned short)*seq1Ptr++;
|
||||
*iseq1Ptr++ |= (WebRtc_Word32)*seq1Ptr++ << 16;
|
||||
|
||||
}
|
||||
|
||||
if(dim_seq%2)
|
||||
{
|
||||
*(iseq1Ptr-1) &= 0x0000ffff;
|
||||
}
|
||||
*iseq1Ptr = 0;
|
||||
iseq1Ptr++;
|
||||
*iseq1Ptr = 0;
|
||||
iseq1Ptr++;
|
||||
*iseq1Ptr = 0;
|
||||
|
||||
if(step_seq2 < 0)
|
||||
{
|
||||
seq2Ptr = seq2 - dim_cross_correlation + 1;
|
||||
CrossCorrPtr = &cross_correlation[dim_cross_correlation - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
seq2Ptr = seq2;
|
||||
CrossCorrPtr = cross_correlation;
|
||||
}
|
||||
|
||||
len = dim_seq + dim_cross_correlation - 1;
|
||||
i_len = (len + 1) >> 1;
|
||||
iseq2Ptr = iseq2;
|
||||
|
||||
iseq3Ptr = iseq3;
|
||||
for(i = 0; i < i_len; i++)
|
||||
{
|
||||
*iseq2Ptr = (unsigned short)*seq2Ptr++;
|
||||
*iseq3Ptr = (unsigned short)*seq2Ptr;
|
||||
*iseq2Ptr++ |= (WebRtc_Word32)*seq2Ptr++ << 16;
|
||||
*iseq3Ptr++ |= (WebRtc_Word32)*seq2Ptr << 16;
|
||||
}
|
||||
|
||||
if(len % 2)
|
||||
{
|
||||
iseq2[i_len - 1] &= 0x0000ffff;
|
||||
iseq3[i_len - 1] = 0;
|
||||
}
|
||||
else
|
||||
iseq3[i_len - 1] &= 0x0000ffff;
|
||||
|
||||
iseq2[i_len] = 0;
|
||||
iseq3[i_len] = 0;
|
||||
iseq2[i_len + 1] = 0;
|
||||
iseq3[i_len + 1] = 0;
|
||||
iseq2[i_len + 2] = 0;
|
||||
iseq3[i_len + 2] = 0;
|
||||
|
||||
// Set pointer to start value
|
||||
iseq2Ptr = iseq2;
|
||||
iseq3Ptr = iseq3;
|
||||
|
||||
i_len = (dim_seq + 7) >> 3;
|
||||
for (i = 0; i < dim_cross_correlation; i++)
|
||||
{
|
||||
|
||||
iseq1Ptr = iseq1;
|
||||
|
||||
macc40 = 0;
|
||||
|
||||
_WriteCoProcessor(macc40, 0);
|
||||
|
||||
if((i & 1))
|
||||
{
|
||||
iseq3Ptr = iseq3 + (i >> 1);
|
||||
for (j = i_len; j > 0; j--)
|
||||
{
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++);
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++);
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++);
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iseq2Ptr = iseq2 + (i >> 1);
|
||||
for (j = i_len; j > 0; j--)
|
||||
{
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++);
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++);
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++);
|
||||
_SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
macc40 = _ReadCoProcessor(0);
|
||||
*CrossCorrPtr = (WebRtc_Word32)(macc40 >> right_shifts);
|
||||
CrossCorrPtr += step_seq2;
|
||||
}
|
||||
#else // #ifdef _XSCALE_OPT_
|
||||
#ifdef _ARM_OPT_
|
||||
WebRtc_Word16 dim_seq8 = (dim_seq >> 3) << 3;
|
||||
#endif
|
||||
|
||||
CrossCorrPtr = cross_correlation;
|
||||
|
||||
for (i = 0; i < dim_cross_correlation; i++)
|
||||
{
|
||||
// Set the pointer to the static vector, set the pointer to the sliding vector
|
||||
// and initialize cross_correlation
|
||||
seq1Ptr = seq1;
|
||||
seq2Ptr = seq2 + (step_seq2 * i);
|
||||
(*CrossCorrPtr) = 0;
|
||||
|
||||
#ifndef _ARM_OPT_
|
||||
#ifdef _WIN32
|
||||
#pragma message("NOTE: default implementation is used")
|
||||
#endif
|
||||
// Perform the cross correlation
|
||||
for (j = 0; j < dim_seq; j++)
|
||||
{
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
}
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#pragma message("NOTE: _ARM_OPT_ optimizations are used")
|
||||
#endif
|
||||
if (right_shifts == 0)
|
||||
{
|
||||
// Perform the optimized cross correlation
|
||||
for (j = 0; j < dim_seq8; j = j + 8)
|
||||
{
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
}
|
||||
|
||||
for (j = dim_seq8; j < dim_seq; j++)
|
||||
{
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
}
|
||||
}
|
||||
else // right_shifts != 0
|
||||
|
||||
{
|
||||
// Perform the optimized cross correlation
|
||||
for (j = 0; j < dim_seq8; j = j + 8)
|
||||
{
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
}
|
||||
|
||||
for (j = dim_seq8; j < dim_seq; j++)
|
||||
{
|
||||
(*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr),
|
||||
right_shifts);
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
CrossCorrPtr++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* decode_B.c
|
||||
*
|
||||
* This file contains definition of funtions for decoding.
|
||||
* Decoding of lower-band, including normal-decoding and RCU decoding.
|
||||
* Decoding of upper-band, including 8-12 kHz, when the bandwidth is
|
||||
* 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "codec.h"
|
||||
#include "entropy_coding.h"
|
||||
#include "pitch_estimator.h"
|
||||
#include "bandwidth_estimator.h"
|
||||
#include "structs.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* function to decode the bitstream
|
||||
* returns the total number of bytes in the stream
|
||||
*/
|
||||
int
|
||||
WebRtcIsac_DecodeLb(
|
||||
float* signal_out,
|
||||
ISACLBDecStruct* ISACdecLB_obj,
|
||||
WebRtc_Word16* current_framesamples,
|
||||
WebRtc_Word16 isRCUPayload)
|
||||
{
|
||||
int k, model;
|
||||
int len, err;
|
||||
WebRtc_Word16 bandwidthInd;
|
||||
|
||||
float LP_dec_float[FRAMESAMPLES_HALF];
|
||||
float HP_dec_float[FRAMESAMPLES_HALF];
|
||||
|
||||
double LPw[FRAMESAMPLES_HALF];
|
||||
double HPw[FRAMESAMPLES_HALF];
|
||||
double LPw_pf[FRAMESAMPLES_HALF];
|
||||
|
||||
double lo_filt_coef[(ORDERLO+1)*SUBFRAMES];
|
||||
double hi_filt_coef[(ORDERHI+1)*SUBFRAMES];
|
||||
|
||||
double real_f[FRAMESAMPLES_HALF];
|
||||
double imag_f[FRAMESAMPLES_HALF];
|
||||
|
||||
double PitchLags[4];
|
||||
double PitchGains[4];
|
||||
double AvgPitchGain;
|
||||
WebRtc_Word16 PitchGains_Q12[4];
|
||||
WebRtc_Word16 AvgPitchGain_Q12;
|
||||
|
||||
float gain;
|
||||
|
||||
int frame_nb; /* counter */
|
||||
int frame_mode; /* 0 for 20ms and 30ms, 1 for 60ms */
|
||||
int processed_samples;
|
||||
|
||||
(ISACdecLB_obj->bitstr_obj).W_upper = 0xFFFFFFFF;
|
||||
(ISACdecLB_obj->bitstr_obj).streamval = 0;
|
||||
(ISACdecLB_obj->bitstr_obj).stream_index = 0;
|
||||
|
||||
len = 0;
|
||||
|
||||
/* decode framelength and BW estimation - not used,
|
||||
only for stream pointer*/
|
||||
err = WebRtcIsac_DecodeFrameLen(&ISACdecLB_obj->bitstr_obj,
|
||||
current_framesamples);
|
||||
if (err < 0) { // error check
|
||||
return err;
|
||||
}
|
||||
|
||||
/* frame_mode: 0, or 1 */
|
||||
frame_mode = *current_framesamples/MAX_FRAMESAMPLES;
|
||||
/* processed_samples: either 320 (20ms) or 480 (30, 60 ms) */
|
||||
processed_samples = *current_framesamples/(frame_mode+1);
|
||||
|
||||
err = WebRtcIsac_DecodeSendBW(&ISACdecLB_obj->bitstr_obj, &bandwidthInd);
|
||||
if (err < 0) { // error check
|
||||
return err;
|
||||
}
|
||||
|
||||
/* one loop if it's one frame (20 or 30ms), 2 loops if 2 frames
|
||||
bundled together (60ms) */
|
||||
for (frame_nb = 0; frame_nb <= frame_mode; frame_nb++) {
|
||||
/* decode & dequantize pitch parameters */
|
||||
err = WebRtcIsac_DecodePitchGain(&(ISACdecLB_obj->bitstr_obj),
|
||||
PitchGains_Q12);
|
||||
if (err < 0) { // error check
|
||||
return err;
|
||||
}
|
||||
|
||||
err = WebRtcIsac_DecodePitchLag(&ISACdecLB_obj->bitstr_obj,
|
||||
PitchGains_Q12, PitchLags);
|
||||
if (err < 0) { // error check
|
||||
return err;
|
||||
}
|
||||
|
||||
AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] +
|
||||
PitchGains_Q12[2] + PitchGains_Q12[3])>>2;
|
||||
|
||||
/* decode & dequantize FiltCoef */
|
||||
err = WebRtcIsac_DecodeLpc(&ISACdecLB_obj->bitstr_obj,
|
||||
lo_filt_coef,hi_filt_coef, &model);
|
||||
if (err < 0) { // error check
|
||||
return err;
|
||||
}
|
||||
/* decode & dequantize spectrum */
|
||||
len = WebRtcIsac_DecodeSpecLb(&ISACdecLB_obj->bitstr_obj,
|
||||
real_f, imag_f, AvgPitchGain_Q12);
|
||||
if (len < 0) { // error check
|
||||
return len;
|
||||
}
|
||||
|
||||
/* inverse transform */
|
||||
WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw,
|
||||
&ISACdecLB_obj->fftstr_obj);
|
||||
|
||||
/* convert PitchGains back to FLOAT for pitchfilter_post */
|
||||
for (k = 0; k < 4; k++) {
|
||||
PitchGains[k] = ((float)PitchGains_Q12[k])/4096;
|
||||
}
|
||||
|
||||
if(isRCUPayload)
|
||||
{
|
||||
for (k = 0; k < 240; k++) {
|
||||
LPw[k] *= RCU_TRANSCODING_SCALE_INVERSE;
|
||||
HPw[k] *= RCU_TRANSCODING_SCALE_INVERSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* inverse pitch filter */
|
||||
WebRtcIsac_PitchfilterPost(LPw, LPw_pf,
|
||||
&ISACdecLB_obj->pitchfiltstr_obj, PitchLags, PitchGains);
|
||||
/* convert AvgPitchGain back to FLOAT for computation of gain */
|
||||
AvgPitchGain = ((float)AvgPitchGain_Q12)/4096;
|
||||
gain = 1.0f - 0.45f * (float)AvgPitchGain;
|
||||
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
/* reduce gain to compensate for pitch enhancer */
|
||||
LPw_pf[ k ] *= gain;
|
||||
}
|
||||
|
||||
if(isRCUPayload)
|
||||
{
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
/* compensation for transcoding gain changes*/
|
||||
LPw_pf[k] *= RCU_TRANSCODING_SCALE;
|
||||
HPw[k] *= RCU_TRANSCODING_SCALE;
|
||||
}
|
||||
}
|
||||
|
||||
/* perceptual post-filtering (using normalized lattice filter) */
|
||||
WebRtcIsac_NormLatticeFilterAr(ORDERLO,
|
||||
ISACdecLB_obj->maskfiltstr_obj.PostStateLoF,
|
||||
(ISACdecLB_obj->maskfiltstr_obj).PostStateLoG,
|
||||
LPw_pf, lo_filt_coef, LP_dec_float);
|
||||
WebRtcIsac_NormLatticeFilterAr(ORDERHI,
|
||||
ISACdecLB_obj->maskfiltstr_obj.PostStateHiF,
|
||||
(ISACdecLB_obj->maskfiltstr_obj).PostStateHiG,
|
||||
HPw, hi_filt_coef, HP_dec_float);
|
||||
|
||||
/* recombine the 2 bands */
|
||||
WebRtcIsac_FilterAndCombineFloat( LP_dec_float, HP_dec_float,
|
||||
signal_out + frame_nb * processed_samples,
|
||||
&ISACdecLB_obj->postfiltbankstr_obj);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This decode function is called when the codec is operating in 16 kHz
|
||||
* bandwidth to decode the upperband, i.e. 8-16 kHz.
|
||||
*
|
||||
* Contrary to lower-band, the upper-band (8-16 kHz) is not split in
|
||||
* frequency, but split to 12 sub-frames, i.e. twice as lower-band.
|
||||
*/
|
||||
int
|
||||
WebRtcIsac_DecodeUb16(
|
||||
float* signal_out,
|
||||
ISACUBDecStruct* ISACdecUB_obj,
|
||||
WebRtc_Word16 isRCUPayload)
|
||||
{
|
||||
int len, err;
|
||||
|
||||
double halfFrameFirst[FRAMESAMPLES_HALF];
|
||||
double halfFrameSecond[FRAMESAMPLES_HALF];
|
||||
|
||||
double percepFilterParam[(UB_LPC_ORDER+1) * (SUBFRAMES<<1) +
|
||||
(UB_LPC_ORDER+1)];
|
||||
|
||||
double real_f[FRAMESAMPLES_HALF];
|
||||
double imag_f[FRAMESAMPLES_HALF];
|
||||
|
||||
len = 0;
|
||||
|
||||
/* decode & dequantize FiltCoef */
|
||||
memset(percepFilterParam, 0, sizeof(percepFilterParam));
|
||||
err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj,
|
||||
percepFilterParam, isac16kHz);
|
||||
if (err < 0) { // error check
|
||||
return err;
|
||||
}
|
||||
|
||||
/* decode & dequantize spectrum */
|
||||
len = WebRtcIsac_DecodeSpecUB16(&ISACdecUB_obj->bitstr_obj, real_f,
|
||||
imag_f);
|
||||
if (len < 0) { // error check
|
||||
return len;
|
||||
}
|
||||
if(isRCUPayload)
|
||||
{
|
||||
int n;
|
||||
for(n = 0; n < 240; n++)
|
||||
{
|
||||
real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
|
||||
imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* inverse transform */
|
||||
WebRtcIsac_Spec2time(real_f, imag_f, halfFrameFirst, halfFrameSecond,
|
||||
&ISACdecUB_obj->fftstr_obj);
|
||||
|
||||
/* perceptual post-filtering (using normalized lattice filter) */
|
||||
WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER,
|
||||
ISACdecUB_obj->maskfiltstr_obj.PostStateLoF,
|
||||
(ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameFirst,
|
||||
&percepFilterParam[(UB_LPC_ORDER+1)], signal_out);
|
||||
|
||||
WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER,
|
||||
ISACdecUB_obj->maskfiltstr_obj.PostStateLoF,
|
||||
(ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameSecond,
|
||||
&percepFilterParam[(UB_LPC_ORDER + 1) * SUBFRAMES + (UB_LPC_ORDER+1)],
|
||||
&signal_out[FRAMESAMPLES_HALF]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* This decode function is called when the codec operates at 0-12 kHz
|
||||
* bandwidth to decode the upperband, i.e. 8-12 kHz.
|
||||
*
|
||||
* At the encoder the upper-band is split into two band, 8-12 kHz & 12-16
|
||||
* kHz, and only 8-12 kHz is encoded. At the decoder, 8-12 kHz band is
|
||||
* reconstructed and 12-16 kHz replaced with zeros. Then two bands
|
||||
* are combined, to reconstruct the upperband 8-16 kHz.
|
||||
*/
|
||||
int
|
||||
WebRtcIsac_DecodeUb12(
|
||||
float* signal_out,
|
||||
ISACUBDecStruct* ISACdecUB_obj,
|
||||
WebRtc_Word16 isRCUPayload)
|
||||
{
|
||||
int len, err;
|
||||
|
||||
float LP_dec_float[FRAMESAMPLES_HALF];
|
||||
float HP_dec_float[FRAMESAMPLES_HALF];
|
||||
|
||||
double LPw[FRAMESAMPLES_HALF];
|
||||
double HPw[FRAMESAMPLES_HALF];
|
||||
|
||||
double percepFilterParam[(UB_LPC_ORDER+1)*SUBFRAMES];
|
||||
|
||||
double real_f[FRAMESAMPLES_HALF];
|
||||
double imag_f[FRAMESAMPLES_HALF];
|
||||
|
||||
len = 0;
|
||||
|
||||
/* decode & dequantize FiltCoef */
|
||||
err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj,
|
||||
percepFilterParam, isac12kHz);
|
||||
if(err < 0) { // error check
|
||||
return err;
|
||||
}
|
||||
|
||||
/* decode & dequantize spectrum */
|
||||
len = WebRtcIsac_DecodeSpecUB12(&ISACdecUB_obj->bitstr_obj,
|
||||
real_f, imag_f);
|
||||
if(len < 0) { // error check
|
||||
return len;
|
||||
}
|
||||
|
||||
if(isRCUPayload)
|
||||
{
|
||||
int n;
|
||||
for(n = 0; n < 240; n++)
|
||||
{
|
||||
real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
|
||||
imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* inverse transform */
|
||||
WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw, &ISACdecUB_obj->fftstr_obj);
|
||||
|
||||
/* perceptual post-filtering (using normalized lattice filter) */
|
||||
WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER,
|
||||
ISACdecUB_obj->maskfiltstr_obj.PostStateLoF,
|
||||
(ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, LPw,
|
||||
percepFilterParam, LP_dec_float);
|
||||
|
||||
/* Zerro for upper-band */
|
||||
memset(HP_dec_float, 0, sizeof(float) * (FRAMESAMPLES_HALF));
|
||||
|
||||
/* recombine the 2 bands */
|
||||
WebRtcIsac_FilterAndCombineFloat(HP_dec_float, LP_dec_float, signal_out,
|
||||
&ISACdecUB_obj->postfiltbankstr_obj);
|
||||
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "structs.h"
|
||||
#include "bandwidth_estimator.h"
|
||||
#include "entropy_coding.h"
|
||||
#include "codec.h"
|
||||
|
||||
|
||||
int
|
||||
WebRtcIsac_EstimateBandwidth(
|
||||
BwEstimatorstr* bwest_str,
|
||||
Bitstr* streamdata,
|
||||
WebRtc_Word32 packet_size,
|
||||
WebRtc_UWord16 rtp_seq_number,
|
||||
WebRtc_UWord32 send_ts,
|
||||
WebRtc_UWord32 arr_ts,
|
||||
enum IsacSamplingRate encoderSampRate,
|
||||
enum IsacSamplingRate decoderSampRate)
|
||||
{
|
||||
WebRtc_Word16 index;
|
||||
WebRtc_Word16 frame_samples;
|
||||
WebRtc_UWord32 sendTimestampIn16kHz;
|
||||
WebRtc_UWord32 arrivalTimestampIn16kHz;
|
||||
WebRtc_UWord32 diffSendTime;
|
||||
WebRtc_UWord32 diffArrivalTime;
|
||||
int err;
|
||||
|
||||
/* decode framelength and BW estimation */
|
||||
err = WebRtcIsac_DecodeFrameLen(streamdata, &frame_samples);
|
||||
if(err < 0) // error check
|
||||
{
|
||||
return err;
|
||||
}
|
||||
err = WebRtcIsac_DecodeSendBW(streamdata, &index);
|
||||
if(err < 0) // error check
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
/* UPDATE ESTIMATES FROM OTHER SIDE */
|
||||
err = WebRtcIsac_UpdateUplinkBwImpl(bwest_str, index, encoderSampRate);
|
||||
if(err < 0)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
// We like BWE to work at 16 kHz sampling rate,
|
||||
// therefore, we have to change the timestamps accordingly.
|
||||
// translate the send timestamp if required
|
||||
diffSendTime = (WebRtc_UWord32)((WebRtc_UWord32)send_ts -
|
||||
(WebRtc_UWord32)bwest_str->senderTimestamp);
|
||||
bwest_str->senderTimestamp = send_ts;
|
||||
|
||||
diffArrivalTime = (WebRtc_UWord32)((WebRtc_UWord32)arr_ts -
|
||||
(WebRtc_UWord32)bwest_str->receiverTimestamp);
|
||||
bwest_str->receiverTimestamp = arr_ts;
|
||||
|
||||
if(decoderSampRate == kIsacSuperWideband)
|
||||
{
|
||||
diffArrivalTime = (WebRtc_UWord32)diffArrivalTime >> 1;
|
||||
diffSendTime = (WebRtc_UWord32)diffSendTime >> 1;
|
||||
}
|
||||
// arrival timestamp in 16 kHz
|
||||
arrivalTimestampIn16kHz = (WebRtc_UWord32)((WebRtc_UWord32)
|
||||
bwest_str->prev_rec_arr_ts + (WebRtc_UWord32)diffArrivalTime);
|
||||
// send timestamp in 16 kHz
|
||||
sendTimestampIn16kHz = (WebRtc_UWord32)((WebRtc_UWord32)
|
||||
bwest_str->prev_rec_send_ts + (WebRtc_UWord32)diffSendTime);
|
||||
|
||||
err = WebRtcIsac_UpdateBandwidthEstimator(bwest_str, rtp_seq_number,
|
||||
(frame_samples * 1000) / FS, sendTimestampIn16kHz,
|
||||
arrivalTimestampIn16kHz, packet_size);
|
||||
// error check
|
||||
if(err < 0)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the divisions
|
||||
* WebRtcSpl_DivU32U16()
|
||||
* WebRtcSpl_DivW32W16()
|
||||
* WebRtcSpl_DivW32W16ResW16()
|
||||
* WebRtcSpl_DivResultInQ31()
|
||||
* WebRtcSpl_DivW32HiLow()
|
||||
*
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
WebRtc_UWord32 WebRtcSpl_DivU32U16(WebRtc_UWord32 num, WebRtc_UWord16 den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (WebRtc_UWord32)(num / den);
|
||||
} else
|
||||
{
|
||||
return (WebRtc_UWord32)0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcSpl_DivW32W16(WebRtc_Word32 num, WebRtc_Word16 den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (WebRtc_Word32)(num / den);
|
||||
} else
|
||||
{
|
||||
return (WebRtc_Word32)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word16 WebRtcSpl_DivW32W16ResW16(WebRtc_Word32 num, WebRtc_Word16 den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (WebRtc_Word16)(num / den);
|
||||
} else
|
||||
{
|
||||
return (WebRtc_Word16)0x7FFF;
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcSpl_DivResultInQ31(WebRtc_Word32 num, WebRtc_Word32 den)
|
||||
{
|
||||
WebRtc_Word32 L_num = num;
|
||||
WebRtc_Word32 L_den = den;
|
||||
WebRtc_Word32 div = 0;
|
||||
int k = 31;
|
||||
int change_sign = 0;
|
||||
|
||||
if (num == 0)
|
||||
return 0;
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
change_sign++;
|
||||
L_num = -num;
|
||||
}
|
||||
if (den < 0)
|
||||
{
|
||||
change_sign++;
|
||||
L_den = -den;
|
||||
}
|
||||
while (k--)
|
||||
{
|
||||
div <<= 1;
|
||||
L_num <<= 1;
|
||||
if (L_num >= L_den)
|
||||
{
|
||||
L_num -= L_den;
|
||||
div++;
|
||||
}
|
||||
}
|
||||
if (change_sign == 1)
|
||||
{
|
||||
div = -div;
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcSpl_DivW32HiLow(WebRtc_Word32 num, WebRtc_Word16 den_hi,
|
||||
WebRtc_Word16 den_low)
|
||||
{
|
||||
WebRtc_Word16 approx, tmp_hi, tmp_low, num_hi, num_low;
|
||||
WebRtc_Word32 tmpW32;
|
||||
|
||||
approx = (WebRtc_Word16)WebRtcSpl_DivW32W16((WebRtc_Word32)0x1FFFFFFF, den_hi);
|
||||
// result in Q14 (Note: 3FFFFFFF = 0.5 in Q30)
|
||||
|
||||
// tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30)
|
||||
tmpW32 = (WEBRTC_SPL_MUL_16_16(den_hi, approx) << 1)
|
||||
+ ((WEBRTC_SPL_MUL_16_16(den_low, approx) >> 15) << 1);
|
||||
// tmpW32 = den * approx
|
||||
|
||||
tmpW32 = (WebRtc_Word32)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
|
||||
|
||||
// Store tmpW32 in hi and low format
|
||||
tmp_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
|
||||
tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((tmpW32
|
||||
- WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1);
|
||||
|
||||
// tmpW32 = 1/den in Q29
|
||||
tmpW32 = ((WEBRTC_SPL_MUL_16_16(tmp_hi, approx) + (WEBRTC_SPL_MUL_16_16(tmp_low, approx)
|
||||
>> 15)) << 1);
|
||||
|
||||
// 1/den in hi and low format
|
||||
tmp_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
|
||||
tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((tmpW32
|
||||
- WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1);
|
||||
|
||||
// Store num in hi and low format
|
||||
num_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(num, 16);
|
||||
num_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((num
|
||||
- WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)num_hi, 16)), 1);
|
||||
|
||||
// num * (1/den) by 32 bit multiplication (result in Q28)
|
||||
|
||||
tmpW32 = (WEBRTC_SPL_MUL_16_16(num_hi, tmp_hi) + (WEBRTC_SPL_MUL_16_16(num_hi, tmp_low)
|
||||
>> 15) + (WEBRTC_SPL_MUL_16_16(num_low, tmp_hi) >> 15));
|
||||
|
||||
// Put result in Q31 (convert from Q28)
|
||||
tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3);
|
||||
|
||||
return tmpW32;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_DotProductWithScale().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
WebRtc_Word32 WebRtcSpl_DotProductWithScale(WebRtc_Word16 *vector1, WebRtc_Word16 *vector2,
|
||||
int length, int scaling)
|
||||
{
|
||||
WebRtc_Word32 sum;
|
||||
int i;
|
||||
#ifdef _ARM_OPT_
|
||||
#pragma message("NOTE: _ARM_OPT_ optimizations are used")
|
||||
WebRtc_Word16 len4 = (length >> 2) << 2;
|
||||
#endif
|
||||
|
||||
sum = 0;
|
||||
|
||||
#ifndef _ARM_OPT_
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1++, *vector2++, scaling);
|
||||
}
|
||||
#else
|
||||
if (scaling == 0)
|
||||
{
|
||||
for (i = 0; i < len4; i = i + 4)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2);
|
||||
vector1++;
|
||||
vector2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2);
|
||||
vector1++;
|
||||
vector2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2);
|
||||
vector1++;
|
||||
vector2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2);
|
||||
vector1++;
|
||||
vector2++;
|
||||
}
|
||||
|
||||
for (i = len4; i < length; i++)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2);
|
||||
vector1++;
|
||||
vector2++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < len4; i = i + 4)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling);
|
||||
vector1++;
|
||||
vector2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling);
|
||||
vector1++;
|
||||
vector2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling);
|
||||
vector1++;
|
||||
vector2++;
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling);
|
||||
vector1++;
|
||||
vector2++;
|
||||
}
|
||||
|
||||
for (i = len4; i < length; i++)
|
||||
{
|
||||
sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling);
|
||||
vector1++;
|
||||
vector2++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return sum;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_DownsampleFast().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
int WebRtcSpl_DownsampleFast(WebRtc_Word16 *in_ptr, WebRtc_Word16 in_length,
|
||||
WebRtc_Word16 *out_ptr, WebRtc_Word16 out_length,
|
||||
WebRtc_Word16 *B, WebRtc_Word16 B_length, WebRtc_Word16 factor,
|
||||
WebRtc_Word16 delay)
|
||||
{
|
||||
WebRtc_Word32 o;
|
||||
int i, j;
|
||||
|
||||
WebRtc_Word16 *downsampled_ptr = out_ptr;
|
||||
WebRtc_Word16 *b_ptr;
|
||||
WebRtc_Word16 *x_ptr;
|
||||
WebRtc_Word16 endpos = delay
|
||||
+ (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(factor, (out_length - 1)) + 1;
|
||||
|
||||
if (in_length < endpos)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = delay; i < endpos; i += factor)
|
||||
{
|
||||
b_ptr = &B[0];
|
||||
x_ptr = &in_ptr[i];
|
||||
|
||||
o = (WebRtc_Word32)2048; // Round val
|
||||
|
||||
for (j = 0; j < B_length; j++)
|
||||
{
|
||||
o += WEBRTC_SPL_MUL_16_16(*b_ptr++, *x_ptr--);
|
||||
}
|
||||
|
||||
o = WEBRTC_SPL_RSHIFT_W32(o, 12);
|
||||
|
||||
// If output is higher than 32768, saturate it. Same with negative side
|
||||
|
||||
*downsampled_ptr++ = WebRtcSpl_SatW32ToW16(o);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,708 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* code_LPC_UB.c
|
||||
*
|
||||
* This file contains definition of functions used to
|
||||
* encode LPC parameters (Shape & gain) of the upper band.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "encode_lpc_swb.h"
|
||||
#include "typedefs.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "lpc_shape_swb12_tables.h"
|
||||
#include "lpc_shape_swb16_tables.h"
|
||||
#include "lpc_gain_swb_tables.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Remove the means from LAR coefficients.
|
||||
*
|
||||
* Input:
|
||||
* -lar : pointer to lar vectors. LAR vectors are
|
||||
* concatenated.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -lar : pointer to mean-removed LAR:s.
|
||||
*
|
||||
*
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_RemoveLarMean(
|
||||
double* lar,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
WebRtc_Word16 vecCntr;
|
||||
WebRtc_Word16 numVec;
|
||||
const double* meanLAR;
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb12;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb16;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(vecCntr = 0; vecCntr < numVec; vecCntr++)
|
||||
{
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
// REMOVE MEAN
|
||||
*lar++ -= meanLAR[coeffCntr];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateIntraVec()
|
||||
*
|
||||
* Remove the correlation amonge the components of LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from left.
|
||||
*
|
||||
* Input:
|
||||
* -inLar : pointer to mean-removed LAR vecrtors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_DecorrelateIntraVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
const double* ptrData;
|
||||
const double* ptrRow;
|
||||
WebRtc_Word16 rowCntr;
|
||||
WebRtc_Word16 colCntr;
|
||||
WebRtc_Word16 larVecCntr;
|
||||
WebRtc_Word16 numVec;
|
||||
const double* decorrMat;
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0];
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0];
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// decorrMat * data
|
||||
//
|
||||
// data is assumed to contain 'numVec' of LAR
|
||||
// vectors (mean removed) each of dimension 'UB_LPC_ORDER'
|
||||
// concatenated one after the other.
|
||||
//
|
||||
|
||||
ptrData = data;
|
||||
for(larVecCntr = 0; larVecCntr < numVec; larVecCntr++)
|
||||
{
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++)
|
||||
{
|
||||
ptrRow = &decorrMat[rowCntr * UB_LPC_ORDER];
|
||||
*out = 0;
|
||||
for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++)
|
||||
{
|
||||
*out += ptrData[colCntr] * ptrRow[colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
ptrData += UB_LPC_ORDER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateInterVec()
|
||||
*
|
||||
* Remover the correlation among mean-removed LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from right.
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to matrix of LAR vectors. The matrix
|
||||
* is stored column-wise.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_DecorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
WebRtc_Word16 rowCntr;
|
||||
WebRtc_Word16 colCntr;
|
||||
const double* decorrMat;
|
||||
WebRtc_Word16 interVecDim;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0];
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0];
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// data * decorrMat
|
||||
//
|
||||
// data is of size 'interVecDim' * 'UB_LPC_ORDER'
|
||||
// That is 'interVecDim' of LAR vectors (mean removed)
|
||||
// in columns each of dimension 'UB_LPC_ORDER'.
|
||||
// matrix is stored column-wise.
|
||||
//
|
||||
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
for(colCntr = 0; colCntr < interVecDim; colCntr++)
|
||||
{
|
||||
out[coeffCntr + colCntr * UB_LPC_ORDER] = 0;
|
||||
for(rowCntr = 0; rowCntr < interVecDim; rowCntr++)
|
||||
{
|
||||
out[coeffCntr + colCntr * UB_LPC_ORDER] +=
|
||||
data[coeffCntr + rowCntr * UB_LPC_ORDER] *
|
||||
decorrMat[rowCntr * interVecDim + colCntr];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeUncorrLar()
|
||||
*
|
||||
* Quantize the uncorrelated parameters.
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated LAR vectors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : quantized version of the input.
|
||||
* -idx : pointer to quantization indices.
|
||||
*/
|
||||
double
|
||||
WebRtcIsac_QuantizeUncorrLar(
|
||||
double* data,
|
||||
int* recIdx,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
WebRtc_Word16 cntr;
|
||||
WebRtc_Word32 idx;
|
||||
WebRtc_Word16 interVecDim;
|
||||
const double* leftRecPoint;
|
||||
double quantizationStepSize;
|
||||
const WebRtc_Word16* numQuantCell;
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12;
|
||||
numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb12;
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16;
|
||||
numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb16;
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Quantize the parametrs.
|
||||
//
|
||||
for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++)
|
||||
{
|
||||
idx = (WebRtc_Word32)floor((*data - leftRecPoint[cntr]) /
|
||||
quantizationStepSize + 0.5);
|
||||
if(idx < 0)
|
||||
{
|
||||
idx = 0;
|
||||
}
|
||||
else if(idx >= numQuantCell[cntr])
|
||||
{
|
||||
idx = numQuantCell[cntr] - 1;
|
||||
}
|
||||
|
||||
*data++ = leftRecPoint[cntr] + idx * quantizationStepSize;
|
||||
*recIdx++ = idx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcParam()
|
||||
*
|
||||
* Get the quantized value of uncorrelated LARs given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantiztion indices.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : pointer to quantized values.
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_DequantizeLpcParam(
|
||||
const int* idx,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
WebRtc_Word16 cntr;
|
||||
WebRtc_Word16 interVecDim;
|
||||
const double* leftRecPoint;
|
||||
double quantizationStepSize;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12;
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16;
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Dequantize given the quantization indices
|
||||
//
|
||||
|
||||
for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++)
|
||||
{
|
||||
*out++ = leftRecPoint[cntr] + *idx++ * quantizationStepSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateIntraVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateIntraVec().
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated parameters.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_CorrelateIntraVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
WebRtc_Word16 vecCntr;
|
||||
WebRtc_Word16 rowCntr;
|
||||
WebRtc_Word16 colCntr;
|
||||
WebRtc_Word16 numVec;
|
||||
const double* ptrData;
|
||||
const double* intraVecDecorrMat;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
intraVecDecorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0];
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
intraVecDecorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ptrData = data;
|
||||
for(vecCntr = 0; vecCntr < numVec; vecCntr++)
|
||||
{
|
||||
for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++)
|
||||
{
|
||||
*out = 0;
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++)
|
||||
{
|
||||
*out += ptrData[rowCntr] *
|
||||
intraVecDecorrMat[rowCntr * UB_LPC_ORDER + colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
ptrData += UB_LPC_ORDER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateInterVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateInterVec().
|
||||
*
|
||||
* Input:
|
||||
* -data
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_CorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
WebRtc_Word16 rowCntr;
|
||||
WebRtc_Word16 colCntr;
|
||||
WebRtc_Word16 interVecDim;
|
||||
double myVec[UB16_LPC_VEC_PER_FRAME];
|
||||
const double* interVecDecorrMat;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0];
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
for(rowCntr = 0; rowCntr < interVecDim; rowCntr++)
|
||||
{
|
||||
myVec[rowCntr] = 0;
|
||||
for(colCntr = 0; colCntr < interVecDim; colCntr++)
|
||||
{
|
||||
myVec[rowCntr] += data[coeffCntr + colCntr * UB_LPC_ORDER] * //*ptrData *
|
||||
interVecDecorrMat[rowCntr * interVecDim + colCntr];
|
||||
//ptrData += UB_LPC_ORDER;
|
||||
}
|
||||
}
|
||||
|
||||
for(rowCntr = 0; rowCntr < interVecDim; rowCntr++)
|
||||
{
|
||||
out[coeffCntr + rowCntr * UB_LPC_ORDER] = myVec[rowCntr];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddLarMean()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to mean-removed LAR:s.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : pointer to LARs.
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_AddLarMean(
|
||||
double* data,
|
||||
WebRtc_Word16 bandwidth)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
WebRtc_Word16 vecCntr;
|
||||
WebRtc_Word16 numVec;
|
||||
const double* meanLAR;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb12;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb16;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(vecCntr = 0; vecCntr < numVec; vecCntr++)
|
||||
{
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
*data++ += meanLAR[coeffCntr];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_ToLogDomainRemoveMean()
|
||||
*
|
||||
* Transform the LPC gain to log domain then remove the mean value.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : pointer to LPC Gain, expecting 6 LPC gains
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : mean-removed in log domain.
|
||||
*/
|
||||
WebRtc_Word16
|
||||
WebRtcIsac_ToLogDomainRemoveMean(
|
||||
double* data)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
data[coeffCntr] = log(data[coeffCntr]) - WebRtcIsac_kMeanLpcGain;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateLPGain()
|
||||
*
|
||||
* Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like
|
||||
* multiplying gain vector with decorrelating matrix.
|
||||
*
|
||||
* Input:
|
||||
* -data : LPC gain in log-domain with mean removed.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated parameters.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecorrelateLPGain(
|
||||
const double* data,
|
||||
double* out)
|
||||
{
|
||||
WebRtc_Word16 rowCntr;
|
||||
WebRtc_Word16 colCntr;
|
||||
|
||||
for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++)
|
||||
{
|
||||
*out = 0;
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++)
|
||||
{
|
||||
*out += data[rowCntr] * WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeLpcGain()
|
||||
*
|
||||
* Quantize the decorrelated log-domain gains.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : uncorrelated LPC gains.
|
||||
*
|
||||
* Output:
|
||||
* -idx : quantization indices
|
||||
* -lpcGain : quantized value of the inpt.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeLpcGain(
|
||||
double* data,
|
||||
int* idx)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
*idx = (int)floor((*data - WebRtcIsac_kLeftRecPointLpcGain[coeffCntr]) /
|
||||
WebRtcIsac_kQSizeLpcGain + 0.5);
|
||||
|
||||
if(*idx < 0)
|
||||
{
|
||||
*idx = 0;
|
||||
}
|
||||
else if(*idx >= WebRtcIsac_kNumQCellLpcGain[coeffCntr])
|
||||
{
|
||||
*idx = WebRtcIsac_kNumQCellLpcGain[coeffCntr] - 1;
|
||||
}
|
||||
*data = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx *
|
||||
WebRtcIsac_kQSizeLpcGain;
|
||||
|
||||
data++;
|
||||
idx++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcGain()
|
||||
*
|
||||
* Get the quantized values given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantization indices.
|
||||
*
|
||||
* Output:
|
||||
* -lpcGains : quantized values of the given parametes.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DequantizeLpcGain(
|
||||
const int* idx,
|
||||
double* out)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
*out = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx *
|
||||
WebRtcIsac_kQSizeLpcGain;
|
||||
out++;
|
||||
idx++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateLpcGain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateLPGain().
|
||||
*
|
||||
* Input:
|
||||
* -data : decorrelated parameters.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parameters.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_CorrelateLpcGain(
|
||||
const double* data,
|
||||
double* out)
|
||||
{
|
||||
WebRtc_Word16 rowCntr;
|
||||
WebRtc_Word16 colCntr;
|
||||
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++)
|
||||
{
|
||||
*out = 0;
|
||||
for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++)
|
||||
{
|
||||
*out += WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr] * data[colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddMeanToLinearDomain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_ToLogDomainRemoveMean().
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : LPC gain in log-domain & mean removed
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : LPC gain in normal domain.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_AddMeanToLinearDomain(
|
||||
double* lpcGains)
|
||||
{
|
||||
WebRtc_Word16 coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
lpcGains[coeffCntr] = exp(lpcGains[coeffCntr] + WebRtcIsac_kMeanLpcGain);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* encode_lpc_swb.h
|
||||
*
|
||||
* This file contains declaration of functions used to
|
||||
* encode LPC parameters (Shape & gain) of the upper band.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "settings.h"
|
||||
#include "structs.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Remove the means from LAR coefficients.
|
||||
*
|
||||
* Input:
|
||||
* -lar : pointer to lar vectors. LAR vectors are
|
||||
* concatenated.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -lar : pointer to mean-removed LAR:s.
|
||||
*
|
||||
*
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_RemoveLarMean(
|
||||
double* lar,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateIntraVec()
|
||||
*
|
||||
* Remove the correlation amonge the components of LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from left.
|
||||
*
|
||||
* Input:
|
||||
* -inLar : pointer to mean-removed LAR vecrtors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecorrelateIntraVec(
|
||||
const double* inLAR,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateInterVec()
|
||||
*
|
||||
* Remover the correlation among mean-removed LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from right.
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to matrix of LAR vectors. The matrix
|
||||
* is stored column-wise.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeUncorrLar()
|
||||
*
|
||||
* Quantize the uncorrelated parameters.
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated LAR vectors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : quantized version of the input.
|
||||
* -idx : pointer to quantization indices.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeUncorrLar(
|
||||
double* data,
|
||||
int* idx,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateIntraVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateIntraVec().
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated parameters.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_CorrelateIntraVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateInterVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateInterVec().
|
||||
*
|
||||
* Input:
|
||||
* -data
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_CorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddLarMean()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to mean-removed LAR:s.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : pointer to LARs.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_AddLarMean(
|
||||
double* data,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcParam()
|
||||
*
|
||||
* Get the quantized value of uncorrelated LARs given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantiztion indices.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : pointer to quantized values.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DequantizeLpcParam(
|
||||
const int* idx,
|
||||
double* out,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_ToLogDomainRemoveMean()
|
||||
*
|
||||
* Transform the LPC gain to log domain then remove the mean value.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : pointer to LPC Gain, expecting 6 LPC gains
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : mean-removed in log domain.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_ToLogDomainRemoveMean(
|
||||
double* lpGains);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateLPGain()
|
||||
*
|
||||
* Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like
|
||||
* multiplying gain vector with decorrelating matrix.
|
||||
*
|
||||
* Input:
|
||||
* -data : LPC gain in log-domain with mean removed.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated parameters.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecorrelateLPGain(
|
||||
const double* data,
|
||||
double* out);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeLpcGain()
|
||||
*
|
||||
* Quantize the decorrelated log-domain gains.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : uncorrelated LPC gains.
|
||||
*
|
||||
* Output:
|
||||
* -idx : quantization indices
|
||||
* -lpcGain : quantized value of the inpt.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeLpcGain(
|
||||
double* lpGains,
|
||||
int* idx);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcGain()
|
||||
*
|
||||
* Get the quantized values given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantization indices.
|
||||
*
|
||||
* Output:
|
||||
* -lpcGains : quantized values of the given parametes.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DequantizeLpcGain(
|
||||
const int* idx,
|
||||
double* lpGains);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateLpcGain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateLPGain().
|
||||
*
|
||||
* Input:
|
||||
* -data : decorrelated parameters.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parameters.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_CorrelateLpcGain(
|
||||
const double* data,
|
||||
double* out);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddMeanToLinearDomain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_ToLogDomainRemoveMean().
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : LPC gain in log-domain & mean removed
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : LPC gain in normal domain.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_AddMeanToLinearDomain(
|
||||
double* lpcGains);
|
||||
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_Energy().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
WebRtc_Word32 WebRtcSpl_Energy(WebRtc_Word16* vector, int vector_length, int* scale_factor)
|
||||
{
|
||||
WebRtc_Word32 en = 0;
|
||||
int i;
|
||||
int scaling = WebRtcSpl_GetScalingSquare(vector, vector_length, vector_length);
|
||||
int looptimes = vector_length;
|
||||
WebRtc_Word16 *vectorptr = vector;
|
||||
|
||||
for (i = 0; i < looptimes; i++)
|
||||
{
|
||||
en += WEBRTC_SPL_MUL_16_16_RSFT(*vectorptr, *vectorptr, scaling);
|
||||
vectorptr++;
|
||||
}
|
||||
*scale_factor = scaling;
|
||||
|
||||
return en;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* entropy_coding.h
|
||||
*
|
||||
* This header file declares all of the functions used to arithmetically
|
||||
* encode the iSAC bistream
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
/* decode complex spectrum (return number of bytes in stream) */
|
||||
int WebRtcIsac_DecodeSpecLb(Bitstr *streamdata,
|
||||
double *fr,
|
||||
double *fi,
|
||||
WebRtc_Word16 AvgPitchGain_Q12);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeSpecUB16()
|
||||
* Decode real and imaginary part of the DFT coefficients, given a bit-stream.
|
||||
* This function is called when the codec is in 0-16 kHz bandwidth.
|
||||
* The decoded DFT coefficient can be transformed to time domain by
|
||||
* WebRtcIsac_Time2Spec().
|
||||
*
|
||||
* Input:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* -*fr : pointer to a buffer where the real part of DFT
|
||||
* coefficients are written to.
|
||||
* -*fi : pointer to a buffer where the imaginary part
|
||||
* of DFT coefficients are written to.
|
||||
*
|
||||
* Return value : < 0 if an error occures
|
||||
* 0 if succeeded.
|
||||
*/
|
||||
int WebRtcIsac_DecodeSpecUB16(
|
||||
Bitstr* streamdata,
|
||||
double* fr,
|
||||
double* fi);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeSpecUB12()
|
||||
* Decode real and imaginary part of the DFT coefficients, given a bit-stream.
|
||||
* This function is called when the codec is in 0-12 kHz bandwidth.
|
||||
* The decoded DFT coefficient can be transformed to time domain by
|
||||
* WebRtcIsac_Time2Spec().
|
||||
*
|
||||
* Input:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* -*fr : pointer to a buffer where the real part of DFT
|
||||
* coefficients are written to.
|
||||
* -*fi : pointer to a buffer where the imaginary part
|
||||
* of DFT coefficients are written to.
|
||||
*
|
||||
* Return value : < 0 if an error occures
|
||||
* 0 if succeeded.
|
||||
*/
|
||||
int WebRtcIsac_DecodeSpecUB12(
|
||||
Bitstr* streamdata,
|
||||
double* fr,
|
||||
double* fi);
|
||||
|
||||
|
||||
/* encode complex spectrum */
|
||||
int WebRtcIsac_EncodeSpecLb(const WebRtc_Word16* fr,
|
||||
const WebRtc_Word16* fi,
|
||||
Bitstr* streamdata,
|
||||
WebRtc_Word16 AvgPitchGain_Q12);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeSpecUB16()
|
||||
* Quantize and encode real and imaginary part of the DFT coefficients.
|
||||
* This function is called when the codec is in 0-16 kHz bandwidth.
|
||||
* The real and imaginary part are computed by calling WebRtcIsac_Time2Spec().
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* -*fr : pointer to a buffer where the real part of DFT
|
||||
* coefficients are stored.
|
||||
* -*fi : pointer to a buffer where the imaginary part
|
||||
* of DFT coefficients are stored.
|
||||
*
|
||||
* Output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Return value : < 0 if an error occures
|
||||
* 0 if succeeded.
|
||||
*/
|
||||
int WebRtcIsac_EncodeSpecUB16(
|
||||
const WebRtc_Word16* fr,
|
||||
const WebRtc_Word16* fi,
|
||||
Bitstr* streamdata);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeSpecUB12()
|
||||
* Quantize and encode real and imaginary part of the DFT coefficients.
|
||||
* This function is called when the codec is in 0-12 kHz bandwidth.
|
||||
* The real and imaginary part are computed by calling WebRtcIsac_Time2Spec().
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* -*fr : pointer to a buffer where the real part of DFT
|
||||
* coefficients are stored.
|
||||
* -*fi : pointer to a buffer where the imaginary part
|
||||
* of DFT coefficients are stored.
|
||||
*
|
||||
* Output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Return value : < 0 if an error occures
|
||||
* 0 if succeeded.
|
||||
*/
|
||||
int WebRtcIsac_EncodeSpecUB12(
|
||||
const WebRtc_Word16* fr,
|
||||
const WebRtc_Word16* fi,
|
||||
Bitstr* streamdata);
|
||||
|
||||
|
||||
/* decode & dequantize LPC Coef */
|
||||
int WebRtcIsac_DecodeLpcCoef(Bitstr *streamdata, double *LPCCoef, int *outmodel);
|
||||
int WebRtcIsac_DecodeLpcCoefUB(
|
||||
Bitstr* streamdata,
|
||||
double* lpcVecs,
|
||||
double* percepFilterGains,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
int WebRtcIsac_DecodeLpc(Bitstr *streamdata, double *LPCCoef_lo, double *LPCCoef_hi, int *outmodel);
|
||||
|
||||
/* quantize & code LPC Coef */
|
||||
void WebRtcIsac_EncodeLpcLb(double *LPCCoef_lo, double *LPCCoef_hi, int *model, double *size, Bitstr *streamdata, ISAC_SaveEncData_t* encData);
|
||||
void WebRtcIsac_EncodeLpcGainLb(double *LPCCoef_lo, double *LPCCoef_hi, int model, Bitstr *streamdata, ISAC_SaveEncData_t* encData);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcUB()
|
||||
* Encode LPC parameters, given as A-polynomial, of upper-band. The encoding
|
||||
* is performed in LAR domain.
|
||||
* For the upper-band, we compute and encode LPC of some sub-frames, LPC of
|
||||
* other sub-frames are computed by linear interpolation, in LAR domain. This
|
||||
* function performs the interpolation and returns the LPC of all sub-frames.
|
||||
*
|
||||
* Inputs:
|
||||
* - lpcCoef : a buffer containing A-polynomials of sub-frames
|
||||
* (excluding first coefficient that is 1).
|
||||
* - bandwidth : specifies if the codec is operating at 0-12 kHz
|
||||
* or 0-16 kHz mode.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - interpolLPCCoeff : Decoded and interpolated LPC (A-polynomial)
|
||||
* of all sub-frames.
|
||||
* If LP analysis is of order K, and there are N
|
||||
* sub-frames then this is a buffer of size
|
||||
* (k + 1) * N, each vector starts with the LPC gain
|
||||
* of the corresponding sub-frame. The LPC gains
|
||||
* are encoded and inserted after this function is
|
||||
* called. The first A-coefficient which is 1 is not
|
||||
* included.
|
||||
*
|
||||
* Return value : 0 if encoding is successful,
|
||||
* <0 if failed to encode.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_EncodeLpcUB(
|
||||
double* lpcCoeff,
|
||||
Bitstr* streamdata,
|
||||
double* interpolLPCCoeff,
|
||||
WebRtc_Word16 bandwidth,
|
||||
ISACUBSaveEncDataStruct* encData);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeInterpolLpcUb()
|
||||
* Decode LPC coefficients and interpolate to get the coefficients fo all
|
||||
* sub-frmaes.
|
||||
*
|
||||
* Inputs:
|
||||
* - bandwidth : spepecifies if the codec is in 0-12 kHz or
|
||||
* 0-16 kHz mode.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - percepFilterParam : Decoded and interpolated LPC (A-polynomial) of
|
||||
* all sub-frames.
|
||||
* If LP analysis is of order K, and there are N
|
||||
* sub-frames then this is a buffer of size
|
||||
* (k + 1) * N, each vector starts with the LPC gain
|
||||
* of the corresponding sub-frame. The LPC gains
|
||||
* are encoded and inserted after this function is
|
||||
* called. The first A-coefficient which is 1 is not
|
||||
* included.
|
||||
*
|
||||
* Return value : 0 if encoding is successful,
|
||||
* <0 if failed to encode.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecodeInterpolLpcUb(
|
||||
Bitstr* streamdata,
|
||||
double* percepFilterParam,
|
||||
WebRtc_Word16 bandwidth);
|
||||
|
||||
/* decode & dequantize RC */
|
||||
int WebRtcIsac_DecodeRc(Bitstr *streamdata, WebRtc_Word16 *RCQ15);
|
||||
|
||||
/* quantize & code RC */
|
||||
void WebRtcIsac_EncodeRc(WebRtc_Word16 *RCQ15, Bitstr *streamdata);
|
||||
|
||||
/* decode & dequantize squared Gain */
|
||||
int WebRtcIsac_DecodeGain2(Bitstr *streamdata, WebRtc_Word32 *Gain2);
|
||||
|
||||
/* quantize & code squared Gain (input is squared gain) */
|
||||
int WebRtcIsac_EncodeGain2(WebRtc_Word32 *gain2, Bitstr *streamdata);
|
||||
|
||||
void WebRtcIsac_EncodePitchGain(WebRtc_Word16* PitchGains_Q12, Bitstr* streamdata, ISAC_SaveEncData_t* encData);
|
||||
|
||||
void WebRtcIsac_EncodePitchLag(double* PitchLags, WebRtc_Word16* PitchGain_Q12, Bitstr* streamdata, ISAC_SaveEncData_t* encData);
|
||||
|
||||
int WebRtcIsac_DecodePitchGain(Bitstr *streamdata, WebRtc_Word16 *PitchGain_Q12);
|
||||
int WebRtcIsac_DecodePitchLag(Bitstr *streamdata, WebRtc_Word16 *PitchGain_Q12, double *PitchLag);
|
||||
|
||||
int WebRtcIsac_DecodeFrameLen(Bitstr *streamdata, WebRtc_Word16 *framelength);
|
||||
int WebRtcIsac_EncodeFrameLen(WebRtc_Word16 framelength, Bitstr *streamdata);
|
||||
int WebRtcIsac_DecodeSendBW(Bitstr *streamdata, WebRtc_Word16 *BWno);
|
||||
void WebRtcIsac_EncodeReceiveBw(int *BWno, Bitstr *streamdata);
|
||||
|
||||
/* step-down */
|
||||
void WebRtcIsac_Poly2Rc(double *a, int N, double *RC);
|
||||
|
||||
/* step-up */
|
||||
void WebRtcIsac_Rc2Poly(double *RC, int N, double *a);
|
||||
|
||||
void WebRtcIsac_TranscodeLPCCoef(double *LPCCoef_lo, double *LPCCoef_hi, int model,
|
||||
int *index_g);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcGainUb()
|
||||
* Encode LPC gains of sub-Frames.
|
||||
*
|
||||
* Input/outputs:
|
||||
* - lpGains : a buffer which contains 'SUBFRAME' number of
|
||||
* LP gains to be encoded. The input values are
|
||||
* overwritten by the quantized values.
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - lpcGainIndex : quantization indices for lpc gains, these will
|
||||
* be stored to be used for FEC.
|
||||
*/
|
||||
void WebRtcIsac_EncodeLpcGainUb(
|
||||
double* lpGains,
|
||||
Bitstr* streamdata,
|
||||
int* lpcGainIndex);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcGainUb()
|
||||
* Store LPC gains of sub-Frames in 'streamdata'.
|
||||
*
|
||||
* Input:
|
||||
* - lpGains : a buffer which contains 'SUBFRAME' number of
|
||||
* LP gains to be encoded.
|
||||
* Input/outputs:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
*/
|
||||
void WebRtcIsac_StoreLpcGainUb(
|
||||
double* lpGains,
|
||||
Bitstr* streamdata);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeLpcGainUb()
|
||||
* Decode the LPC gain of sub-frames.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - lpGains : a buffer where decoded LPC gians will be stored.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecodeLpcGainUb(
|
||||
double* lpGains,
|
||||
Bitstr* streamdata);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeBandwidth()
|
||||
* Encode if the bandwidth of encoded audio is 0-12 kHz or 0-16 kHz.
|
||||
*
|
||||
* Input:
|
||||
* - bandwidth : an enumerator specifying if the codec in is
|
||||
* 0-12 kHz or 0-16 kHz mode.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_EncodeBandwidth(
|
||||
enum ISACBandwidth bandwidth,
|
||||
Bitstr* streamData);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeBandwidth()
|
||||
* Decode the bandwidth of the encoded audio, i.e. if the bandwidth is 0-12 kHz
|
||||
* or 0-16 kHz.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - bandwidth : an enumerator specifying if the codec is in
|
||||
* 0-12 kHz or 0-16 kHz mode.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecodeBandwidth(
|
||||
Bitstr* streamData,
|
||||
enum ISACBandwidth* bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeJitterInfo()
|
||||
* Decode the jitter information.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Input:
|
||||
* - jitterInfo : one bit of info specifying if the channel is
|
||||
* in high/low jitter. Zero indicates low jitter
|
||||
* and one indicates high jitter.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_EncodeJitterInfo(
|
||||
WebRtc_Word32 jitterIndex,
|
||||
Bitstr* streamData);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeJitterInfo()
|
||||
* Decode the jitter information.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - jitterInfo : one bit of info specifying if the channel is
|
||||
* in high/low jitter. Zero indicates low jitter
|
||||
* and one indicates high jitter.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
WebRtc_Word16 WebRtcIsac_DecodeJitterInfo(
|
||||
Bitstr* streamData,
|
||||
WebRtc_Word32* jitterInfo);
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */
|
||||
@@ -0,0 +1,947 @@
|
||||
/*
|
||||
* Copyright(c)1995,97 Mark Olesen <olesen@me.QueensU.CA>
|
||||
* Queen's Univ at Kingston (Canada)
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for
|
||||
* any purpose without fee is hereby granted, provided that this
|
||||
* entire notice is included in all copies of any software which is
|
||||
* or includes a copy or modification of this software and in all
|
||||
* copies of the supporting documentation for such software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S
|
||||
* UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY
|
||||
* KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
|
||||
* FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*
|
||||
* All of which is to say that you can do what you like with this
|
||||
* source code provided you don't try to sell it as your own and you
|
||||
* include an unaltered copy of this message (including the
|
||||
* copyright).
|
||||
*
|
||||
* It is also implicitly understood that bug fixes and improvements
|
||||
* should make their way back to the general Internet community so
|
||||
* that everyone benefits.
|
||||
*
|
||||
* Changes:
|
||||
* Trivial type modifications by the WebRTC authors.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* File:
|
||||
* WebRtcIsac_Fftn.c
|
||||
*
|
||||
* Public:
|
||||
* WebRtcIsac_Fftn / fftnf ();
|
||||
*
|
||||
* Private:
|
||||
* WebRtcIsac_Fftradix / fftradixf ();
|
||||
*
|
||||
* Descript:
|
||||
* multivariate complex Fourier transform, computed in place
|
||||
* using mixed-radix Fast Fourier Transform algorithm.
|
||||
*
|
||||
* Fortran code by:
|
||||
* RC Singleton, Stanford Research Institute, Sept. 1968
|
||||
*
|
||||
* translated by f2c (version 19950721).
|
||||
*
|
||||
* int WebRtcIsac_Fftn (int ndim, const int dims[], REAL Re[], REAL Im[],
|
||||
* int iSign, double scaling);
|
||||
*
|
||||
* NDIM = the total number dimensions
|
||||
* DIMS = a vector of array sizes
|
||||
* if NDIM is zero then DIMS must be zero-terminated
|
||||
*
|
||||
* RE and IM hold the real and imaginary components of the data, and return
|
||||
* the resulting real and imaginary Fourier coefficients. Multidimensional
|
||||
* data *must* be allocated contiguously. There is no limit on the number
|
||||
* of dimensions.
|
||||
*
|
||||
* ISIGN = the sign of the complex exponential (ie, forward or inverse FFT)
|
||||
* the magnitude of ISIGN (normally 1) is used to determine the
|
||||
* correct indexing increment (see below).
|
||||
*
|
||||
* SCALING = normalizing constant by which the final result is *divided*
|
||||
* if SCALING == -1, normalize by total dimension of the transform
|
||||
* if SCALING < -1, normalize by the square-root of the total dimension
|
||||
*
|
||||
* example:
|
||||
* tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3]
|
||||
*
|
||||
* int dims[3] = {n1,n2,n3}
|
||||
* WebRtcIsac_Fftn (3, dims, Re, Im, 1, scaling);
|
||||
*
|
||||
*-----------------------------------------------------------------------*
|
||||
* int WebRtcIsac_Fftradix (REAL Re[], REAL Im[], size_t nTotal, size_t nPass,
|
||||
* size_t nSpan, int iSign, size_t max_factors,
|
||||
* size_t max_perm);
|
||||
*
|
||||
* RE, IM - see above documentation
|
||||
*
|
||||
* Although there is no limit on the number of dimensions, WebRtcIsac_Fftradix() must
|
||||
* be called once for each dimension, but the calls may be in any order.
|
||||
*
|
||||
* NTOTAL = the total number of complex data values
|
||||
* NPASS = the dimension of the current variable
|
||||
* NSPAN/NPASS = the spacing of consecutive data values while indexing the
|
||||
* current variable
|
||||
* ISIGN - see above documentation
|
||||
*
|
||||
* example:
|
||||
* tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3]
|
||||
*
|
||||
* WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n1, n1, 1, maxf, maxp);
|
||||
* WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n2, n1*n2, 1, maxf, maxp);
|
||||
* WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n3, n1*n2*n3, 1, maxf, maxp);
|
||||
*
|
||||
* single-variate transform,
|
||||
* NTOTAL = N = NSPAN = (number of complex data values),
|
||||
*
|
||||
* WebRtcIsac_Fftradix (Re, Im, n, n, n, 1, maxf, maxp);
|
||||
*
|
||||
* The data can also be stored in a single array with alternating real and
|
||||
* imaginary parts, the magnitude of ISIGN is changed to 2 to give correct
|
||||
* indexing increment, and data [0] and data [1] used to pass the initial
|
||||
* addresses for the sequences of real and imaginary values,
|
||||
*
|
||||
* example:
|
||||
* REAL data [2*NTOTAL];
|
||||
* WebRtcIsac_Fftradix ( &data[0], &data[1], NTOTAL, nPass, nSpan, 2, maxf, maxp);
|
||||
*
|
||||
* for temporary allocation:
|
||||
*
|
||||
* MAX_FACTORS >= the maximum prime factor of NPASS
|
||||
* MAX_PERM >= the number of prime factors of NPASS. In addition,
|
||||
* if the square-free portion K of NPASS has two or more prime
|
||||
* factors, then MAX_PERM >= (K-1)
|
||||
*
|
||||
* storage in FACTOR for a maximum of 15 prime factors of NPASS. if NPASS
|
||||
* has more than one square-free factor, the product of the square-free
|
||||
* factors must be <= 210 array storage for maximum prime factor of 23 the
|
||||
* following two constants should agree with the array dimensions.
|
||||
*
|
||||
*----------------------------------------------------------------------*/
|
||||
#include "fft.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
||||
/* double precision routine */
|
||||
static int
|
||||
WebRtcIsac_Fftradix (double Re[], double Im[],
|
||||
size_t nTotal, size_t nPass, size_t nSpan, int isign,
|
||||
int max_factors, unsigned int max_perm,
|
||||
FFTstr *fftstate);
|
||||
|
||||
|
||||
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846264338327950288
|
||||
#endif
|
||||
|
||||
#ifndef SIN60
|
||||
# define SIN60 0.86602540378443865 /* sin(60 deg) */
|
||||
# define COS72 0.30901699437494742 /* cos(72 deg) */
|
||||
# define SIN72 0.95105651629515357 /* sin(72 deg) */
|
||||
#endif
|
||||
|
||||
# define REAL double
|
||||
# define FFTN WebRtcIsac_Fftn
|
||||
# define FFTNS "fftn"
|
||||
# define FFTRADIX WebRtcIsac_Fftradix
|
||||
# define FFTRADIXS "fftradix"
|
||||
|
||||
|
||||
int WebRtcIsac_Fftns(unsigned int ndim, const int dims[],
|
||||
double Re[],
|
||||
double Im[],
|
||||
int iSign,
|
||||
double scaling,
|
||||
FFTstr *fftstate)
|
||||
{
|
||||
|
||||
size_t nSpan, nPass, nTotal;
|
||||
unsigned int i;
|
||||
int ret, max_factors, max_perm;
|
||||
|
||||
/*
|
||||
* tally the number of elements in the data array
|
||||
* and determine the number of dimensions
|
||||
*/
|
||||
nTotal = 1;
|
||||
if (ndim && dims [0])
|
||||
{
|
||||
for (i = 0; i < ndim; i++)
|
||||
{
|
||||
if (dims [i] <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
nTotal *= dims [i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ndim = 0;
|
||||
for (i = 0; dims [i]; i++)
|
||||
{
|
||||
if (dims [i] <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
nTotal *= dims [i];
|
||||
ndim++;
|
||||
}
|
||||
}
|
||||
|
||||
/* determine maximum number of factors and permuations */
|
||||
#if 1
|
||||
/*
|
||||
* follow John Beale's example, just use the largest dimension and don't
|
||||
* worry about excess allocation. May be someone else will do it?
|
||||
*/
|
||||
max_factors = max_perm = 1;
|
||||
for (i = 0; i < ndim; i++)
|
||||
{
|
||||
nSpan = dims [i];
|
||||
if ((int)nSpan > max_factors)
|
||||
{
|
||||
max_factors = (int)nSpan;
|
||||
}
|
||||
if ((int)nSpan > max_perm)
|
||||
{
|
||||
max_perm = (int)nSpan;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* use the constants used in the original Fortran code */
|
||||
max_factors = 23;
|
||||
max_perm = 209;
|
||||
#endif
|
||||
/* loop over the dimensions: */
|
||||
nPass = 1;
|
||||
for (i = 0; i < ndim; i++)
|
||||
{
|
||||
nSpan = dims [i];
|
||||
nPass *= nSpan;
|
||||
ret = FFTRADIX (Re, Im, nTotal, nSpan, nPass, iSign,
|
||||
max_factors, max_perm, fftstate);
|
||||
/* exit, clean-up already done */
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Divide through by the normalizing constant: */
|
||||
if (scaling && scaling != 1.0)
|
||||
{
|
||||
if (iSign < 0) iSign = -iSign;
|
||||
if (scaling < 0.0)
|
||||
{
|
||||
scaling = (double)nTotal;
|
||||
if (scaling < -1.0)
|
||||
scaling = sqrt (scaling);
|
||||
}
|
||||
scaling = 1.0 / scaling; /* multiply is often faster */
|
||||
for (i = 0; i < nTotal; i += iSign)
|
||||
{
|
||||
Re [i] *= scaling;
|
||||
Im [i] *= scaling;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* singleton's mixed radix routine
|
||||
*
|
||||
* could move allocation out to WebRtcIsac_Fftn(), but leave it here so that it's
|
||||
* possible to make this a standalone function
|
||||
*/
|
||||
|
||||
static int FFTRADIX (REAL Re[],
|
||||
REAL Im[],
|
||||
size_t nTotal,
|
||||
size_t nPass,
|
||||
size_t nSpan,
|
||||
int iSign,
|
||||
int max_factors,
|
||||
unsigned int max_perm,
|
||||
FFTstr *fftstate)
|
||||
{
|
||||
int ii, mfactor, kspan, ispan, inc;
|
||||
int j, jc, jf, jj, k, k1, k2, k3, k4, kk, kt, nn, ns, nt;
|
||||
|
||||
|
||||
REAL radf;
|
||||
REAL c1, c2, c3, cd, aa, aj, ak, ajm, ajp, akm, akp;
|
||||
REAL s1, s2, s3, sd, bb, bj, bk, bjm, bjp, bkm, bkp;
|
||||
|
||||
REAL *Rtmp = NULL; /* temp space for real part*/
|
||||
REAL *Itmp = NULL; /* temp space for imaginary part */
|
||||
REAL *Cos = NULL; /* Cosine values */
|
||||
REAL *Sin = NULL; /* Sine values */
|
||||
|
||||
REAL s60 = SIN60; /* sin(60 deg) */
|
||||
REAL c72 = COS72; /* cos(72 deg) */
|
||||
REAL s72 = SIN72; /* sin(72 deg) */
|
||||
REAL pi2 = M_PI; /* use PI first, 2 PI later */
|
||||
|
||||
|
||||
fftstate->SpaceAlloced = 0;
|
||||
fftstate->MaxPermAlloced = 0;
|
||||
|
||||
|
||||
// initialize to avoid warnings
|
||||
k3 = c2 = c3 = s2 = s3 = 0.0;
|
||||
|
||||
if (nPass < 2)
|
||||
return 0;
|
||||
|
||||
/* allocate storage */
|
||||
if (fftstate->SpaceAlloced < max_factors * sizeof (REAL))
|
||||
{
|
||||
#ifdef SUN_BROKEN_REALLOC
|
||||
if (!fftstate->SpaceAlloced) /* first time */
|
||||
{
|
||||
fftstate->SpaceAlloced = max_factors * sizeof (REAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
fftstate->SpaceAlloced = max_factors * sizeof (REAL);
|
||||
#ifdef SUN_BROKEN_REALLOC
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* allow full use of alloc'd space */
|
||||
max_factors = fftstate->SpaceAlloced / sizeof (REAL);
|
||||
}
|
||||
if (fftstate->MaxPermAlloced < max_perm)
|
||||
{
|
||||
#ifdef SUN_BROKEN_REALLOC
|
||||
if (!fftstate->MaxPermAlloced) /* first time */
|
||||
else
|
||||
#endif
|
||||
fftstate->MaxPermAlloced = max_perm;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* allow full use of alloc'd space */
|
||||
max_perm = fftstate->MaxPermAlloced;
|
||||
}
|
||||
if (fftstate->Tmp0 == NULL || fftstate->Tmp1 == NULL || fftstate->Tmp2 == NULL || fftstate->Tmp3 == NULL
|
||||
|| fftstate->Perm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* assign pointers */
|
||||
Rtmp = (REAL *) fftstate->Tmp0;
|
||||
Itmp = (REAL *) fftstate->Tmp1;
|
||||
Cos = (REAL *) fftstate->Tmp2;
|
||||
Sin = (REAL *) fftstate->Tmp3;
|
||||
|
||||
/*
|
||||
* Function Body
|
||||
*/
|
||||
inc = iSign;
|
||||
if (iSign < 0) {
|
||||
s72 = -s72;
|
||||
s60 = -s60;
|
||||
pi2 = -pi2;
|
||||
inc = -inc; /* absolute value */
|
||||
}
|
||||
|
||||
/* adjust for strange increments */
|
||||
nt = inc * (int)nTotal;
|
||||
ns = inc * (int)nSpan;
|
||||
kspan = ns;
|
||||
|
||||
nn = nt - inc;
|
||||
jc = ns / (int)nPass;
|
||||
radf = pi2 * (double) jc;
|
||||
pi2 *= 2.0; /* use 2 PI from here on */
|
||||
|
||||
ii = 0;
|
||||
jf = 0;
|
||||
/* determine the factors of n */
|
||||
mfactor = 0;
|
||||
k = (int)nPass;
|
||||
while (k % 16 == 0) {
|
||||
mfactor++;
|
||||
fftstate->factor [mfactor - 1] = 4;
|
||||
k /= 16;
|
||||
}
|
||||
j = 3;
|
||||
jj = 9;
|
||||
do {
|
||||
while (k % jj == 0) {
|
||||
mfactor++;
|
||||
fftstate->factor [mfactor - 1] = j;
|
||||
k /= jj;
|
||||
}
|
||||
j += 2;
|
||||
jj = j * j;
|
||||
} while (jj <= k);
|
||||
if (k <= 4) {
|
||||
kt = mfactor;
|
||||
fftstate->factor [mfactor] = k;
|
||||
if (k != 1)
|
||||
mfactor++;
|
||||
} else {
|
||||
if (k - (k / 4 << 2) == 0) {
|
||||
mfactor++;
|
||||
fftstate->factor [mfactor - 1] = 2;
|
||||
k /= 4;
|
||||
}
|
||||
kt = mfactor;
|
||||
j = 2;
|
||||
do {
|
||||
if (k % j == 0) {
|
||||
mfactor++;
|
||||
fftstate->factor [mfactor - 1] = j;
|
||||
k /= j;
|
||||
}
|
||||
j = ((j + 1) / 2 << 1) + 1;
|
||||
} while (j <= k);
|
||||
}
|
||||
if (kt) {
|
||||
j = kt;
|
||||
do {
|
||||
mfactor++;
|
||||
fftstate->factor [mfactor - 1] = fftstate->factor [j - 1];
|
||||
j--;
|
||||
} while (j);
|
||||
}
|
||||
|
||||
/* test that mfactors is in range */
|
||||
if (mfactor > NFACTOR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* compute fourier transform */
|
||||
for (;;) {
|
||||
sd = radf / (double) kspan;
|
||||
cd = sin(sd);
|
||||
cd = 2.0 * cd * cd;
|
||||
sd = sin(sd + sd);
|
||||
kk = 0;
|
||||
ii++;
|
||||
|
||||
switch (fftstate->factor [ii - 1]) {
|
||||
case 2:
|
||||
/* transform for factor of 2 (including rotation factor) */
|
||||
kspan /= 2;
|
||||
k1 = kspan + 2;
|
||||
do {
|
||||
do {
|
||||
k2 = kk + kspan;
|
||||
ak = Re [k2];
|
||||
bk = Im [k2];
|
||||
Re [k2] = Re [kk] - ak;
|
||||
Im [k2] = Im [kk] - bk;
|
||||
Re [kk] += ak;
|
||||
Im [kk] += bk;
|
||||
kk = k2 + kspan;
|
||||
} while (kk < nn);
|
||||
kk -= nn;
|
||||
} while (kk < jc);
|
||||
if (kk >= kspan)
|
||||
goto Permute_Results_Label; /* exit infinite loop */
|
||||
do {
|
||||
c1 = 1.0 - cd;
|
||||
s1 = sd;
|
||||
do {
|
||||
do {
|
||||
do {
|
||||
k2 = kk + kspan;
|
||||
ak = Re [kk] - Re [k2];
|
||||
bk = Im [kk] - Im [k2];
|
||||
Re [kk] += Re [k2];
|
||||
Im [kk] += Im [k2];
|
||||
Re [k2] = c1 * ak - s1 * bk;
|
||||
Im [k2] = s1 * ak + c1 * bk;
|
||||
kk = k2 + kspan;
|
||||
} while (kk < (nt-1));
|
||||
k2 = kk - nt;
|
||||
c1 = -c1;
|
||||
kk = k1 - k2;
|
||||
} while (kk > k2);
|
||||
ak = c1 - (cd * c1 + sd * s1);
|
||||
s1 = sd * c1 - cd * s1 + s1;
|
||||
c1 = 2.0 - (ak * ak + s1 * s1);
|
||||
s1 *= c1;
|
||||
c1 *= ak;
|
||||
kk += jc;
|
||||
} while (kk < k2);
|
||||
k1 += inc + inc;
|
||||
kk = (k1 - kspan + 1) / 2 + jc - 1;
|
||||
} while (kk < (jc + jc));
|
||||
break;
|
||||
|
||||
case 4: /* transform for factor of 4 */
|
||||
ispan = kspan;
|
||||
kspan /= 4;
|
||||
|
||||
do {
|
||||
c1 = 1.0;
|
||||
s1 = 0.0;
|
||||
do {
|
||||
do {
|
||||
k1 = kk + kspan;
|
||||
k2 = k1 + kspan;
|
||||
k3 = k2 + kspan;
|
||||
akp = Re [kk] + Re [k2];
|
||||
akm = Re [kk] - Re [k2];
|
||||
ajp = Re [k1] + Re [k3];
|
||||
ajm = Re [k1] - Re [k3];
|
||||
bkp = Im [kk] + Im [k2];
|
||||
bkm = Im [kk] - Im [k2];
|
||||
bjp = Im [k1] + Im [k3];
|
||||
bjm = Im [k1] - Im [k3];
|
||||
Re [kk] = akp + ajp;
|
||||
Im [kk] = bkp + bjp;
|
||||
ajp = akp - ajp;
|
||||
bjp = bkp - bjp;
|
||||
if (iSign < 0) {
|
||||
akp = akm + bjm;
|
||||
bkp = bkm - ajm;
|
||||
akm -= bjm;
|
||||
bkm += ajm;
|
||||
} else {
|
||||
akp = akm - bjm;
|
||||
bkp = bkm + ajm;
|
||||
akm += bjm;
|
||||
bkm -= ajm;
|
||||
}
|
||||
/* avoid useless multiplies */
|
||||
if (s1 == 0.0) {
|
||||
Re [k1] = akp;
|
||||
Re [k2] = ajp;
|
||||
Re [k3] = akm;
|
||||
Im [k1] = bkp;
|
||||
Im [k2] = bjp;
|
||||
Im [k3] = bkm;
|
||||
} else {
|
||||
Re [k1] = akp * c1 - bkp * s1;
|
||||
Re [k2] = ajp * c2 - bjp * s2;
|
||||
Re [k3] = akm * c3 - bkm * s3;
|
||||
Im [k1] = akp * s1 + bkp * c1;
|
||||
Im [k2] = ajp * s2 + bjp * c2;
|
||||
Im [k3] = akm * s3 + bkm * c3;
|
||||
}
|
||||
kk = k3 + kspan;
|
||||
} while (kk < nt);
|
||||
|
||||
c2 = c1 - (cd * c1 + sd * s1);
|
||||
s1 = sd * c1 - cd * s1 + s1;
|
||||
c1 = 2.0 - (c2 * c2 + s1 * s1);
|
||||
s1 *= c1;
|
||||
c1 *= c2;
|
||||
/* values of c2, c3, s2, s3 that will get used next time */
|
||||
c2 = c1 * c1 - s1 * s1;
|
||||
s2 = 2.0 * c1 * s1;
|
||||
c3 = c2 * c1 - s2 * s1;
|
||||
s3 = c2 * s1 + s2 * c1;
|
||||
kk = kk - nt + jc;
|
||||
} while (kk < kspan);
|
||||
kk = kk - kspan + inc;
|
||||
} while (kk < jc);
|
||||
if (kspan == jc)
|
||||
goto Permute_Results_Label; /* exit infinite loop */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* transform for odd factors */
|
||||
#ifdef FFT_RADIX4
|
||||
return -1;
|
||||
break;
|
||||
#else /* FFT_RADIX4 */
|
||||
k = fftstate->factor [ii - 1];
|
||||
ispan = kspan;
|
||||
kspan /= k;
|
||||
|
||||
switch (k) {
|
||||
case 3: /* transform for factor of 3 (optional code) */
|
||||
do {
|
||||
do {
|
||||
k1 = kk + kspan;
|
||||
k2 = k1 + kspan;
|
||||
ak = Re [kk];
|
||||
bk = Im [kk];
|
||||
aj = Re [k1] + Re [k2];
|
||||
bj = Im [k1] + Im [k2];
|
||||
Re [kk] = ak + aj;
|
||||
Im [kk] = bk + bj;
|
||||
ak -= 0.5 * aj;
|
||||
bk -= 0.5 * bj;
|
||||
aj = (Re [k1] - Re [k2]) * s60;
|
||||
bj = (Im [k1] - Im [k2]) * s60;
|
||||
Re [k1] = ak - bj;
|
||||
Re [k2] = ak + bj;
|
||||
Im [k1] = bk + aj;
|
||||
Im [k2] = bk - aj;
|
||||
kk = k2 + kspan;
|
||||
} while (kk < (nn - 1));
|
||||
kk -= nn;
|
||||
} while (kk < kspan);
|
||||
break;
|
||||
|
||||
case 5: /* transform for factor of 5 (optional code) */
|
||||
c2 = c72 * c72 - s72 * s72;
|
||||
s2 = 2.0 * c72 * s72;
|
||||
do {
|
||||
do {
|
||||
k1 = kk + kspan;
|
||||
k2 = k1 + kspan;
|
||||
k3 = k2 + kspan;
|
||||
k4 = k3 + kspan;
|
||||
akp = Re [k1] + Re [k4];
|
||||
akm = Re [k1] - Re [k4];
|
||||
bkp = Im [k1] + Im [k4];
|
||||
bkm = Im [k1] - Im [k4];
|
||||
ajp = Re [k2] + Re [k3];
|
||||
ajm = Re [k2] - Re [k3];
|
||||
bjp = Im [k2] + Im [k3];
|
||||
bjm = Im [k2] - Im [k3];
|
||||
aa = Re [kk];
|
||||
bb = Im [kk];
|
||||
Re [kk] = aa + akp + ajp;
|
||||
Im [kk] = bb + bkp + bjp;
|
||||
ak = akp * c72 + ajp * c2 + aa;
|
||||
bk = bkp * c72 + bjp * c2 + bb;
|
||||
aj = akm * s72 + ajm * s2;
|
||||
bj = bkm * s72 + bjm * s2;
|
||||
Re [k1] = ak - bj;
|
||||
Re [k4] = ak + bj;
|
||||
Im [k1] = bk + aj;
|
||||
Im [k4] = bk - aj;
|
||||
ak = akp * c2 + ajp * c72 + aa;
|
||||
bk = bkp * c2 + bjp * c72 + bb;
|
||||
aj = akm * s2 - ajm * s72;
|
||||
bj = bkm * s2 - bjm * s72;
|
||||
Re [k2] = ak - bj;
|
||||
Re [k3] = ak + bj;
|
||||
Im [k2] = bk + aj;
|
||||
Im [k3] = bk - aj;
|
||||
kk = k4 + kspan;
|
||||
} while (kk < (nn-1));
|
||||
kk -= nn;
|
||||
} while (kk < kspan);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (k != jf) {
|
||||
jf = k;
|
||||
s1 = pi2 / (double) k;
|
||||
c1 = cos(s1);
|
||||
s1 = sin(s1);
|
||||
if (jf > max_factors){
|
||||
return -1;
|
||||
}
|
||||
Cos [jf - 1] = 1.0;
|
||||
Sin [jf - 1] = 0.0;
|
||||
j = 1;
|
||||
do {
|
||||
Cos [j - 1] = Cos [k - 1] * c1 + Sin [k - 1] * s1;
|
||||
Sin [j - 1] = Cos [k - 1] * s1 - Sin [k - 1] * c1;
|
||||
k--;
|
||||
Cos [k - 1] = Cos [j - 1];
|
||||
Sin [k - 1] = -Sin [j - 1];
|
||||
j++;
|
||||
} while (j < k);
|
||||
}
|
||||
do {
|
||||
do {
|
||||
k1 = kk;
|
||||
k2 = kk + ispan;
|
||||
ak = aa = Re [kk];
|
||||
bk = bb = Im [kk];
|
||||
j = 1;
|
||||
k1 += kspan;
|
||||
do {
|
||||
k2 -= kspan;
|
||||
j++;
|
||||
Rtmp [j - 1] = Re [k1] + Re [k2];
|
||||
ak += Rtmp [j - 1];
|
||||
Itmp [j - 1] = Im [k1] + Im [k2];
|
||||
bk += Itmp [j - 1];
|
||||
j++;
|
||||
Rtmp [j - 1] = Re [k1] - Re [k2];
|
||||
Itmp [j - 1] = Im [k1] - Im [k2];
|
||||
k1 += kspan;
|
||||
} while (k1 < k2);
|
||||
Re [kk] = ak;
|
||||
Im [kk] = bk;
|
||||
k1 = kk;
|
||||
k2 = kk + ispan;
|
||||
j = 1;
|
||||
do {
|
||||
k1 += kspan;
|
||||
k2 -= kspan;
|
||||
jj = j;
|
||||
ak = aa;
|
||||
bk = bb;
|
||||
aj = 0.0;
|
||||
bj = 0.0;
|
||||
k = 1;
|
||||
do {
|
||||
k++;
|
||||
ak += Rtmp [k - 1] * Cos [jj - 1];
|
||||
bk += Itmp [k - 1] * Cos [jj - 1];
|
||||
k++;
|
||||
aj += Rtmp [k - 1] * Sin [jj - 1];
|
||||
bj += Itmp [k - 1] * Sin [jj - 1];
|
||||
jj += j;
|
||||
if (jj > jf) {
|
||||
jj -= jf;
|
||||
}
|
||||
} while (k < jf);
|
||||
k = jf - j;
|
||||
Re [k1] = ak - bj;
|
||||
Im [k1] = bk + aj;
|
||||
Re [k2] = ak + bj;
|
||||
Im [k2] = bk - aj;
|
||||
j++;
|
||||
} while (j < k);
|
||||
kk += ispan;
|
||||
} while (kk < nn);
|
||||
kk -= nn;
|
||||
} while (kk < kspan);
|
||||
break;
|
||||
}
|
||||
|
||||
/* multiply by rotation factor (except for factors of 2 and 4) */
|
||||
if (ii == mfactor)
|
||||
goto Permute_Results_Label; /* exit infinite loop */
|
||||
kk = jc;
|
||||
do {
|
||||
c2 = 1.0 - cd;
|
||||
s1 = sd;
|
||||
do {
|
||||
c1 = c2;
|
||||
s2 = s1;
|
||||
kk += kspan;
|
||||
do {
|
||||
do {
|
||||
ak = Re [kk];
|
||||
Re [kk] = c2 * ak - s2 * Im [kk];
|
||||
Im [kk] = s2 * ak + c2 * Im [kk];
|
||||
kk += ispan;
|
||||
} while (kk < nt);
|
||||
ak = s1 * s2;
|
||||
s2 = s1 * c2 + c1 * s2;
|
||||
c2 = c1 * c2 - ak;
|
||||
kk = kk - nt + kspan;
|
||||
} while (kk < ispan);
|
||||
c2 = c1 - (cd * c1 + sd * s1);
|
||||
s1 += sd * c1 - cd * s1;
|
||||
c1 = 2.0 - (c2 * c2 + s1 * s1);
|
||||
s1 *= c1;
|
||||
c2 *= c1;
|
||||
kk = kk - ispan + jc;
|
||||
} while (kk < kspan);
|
||||
kk = kk - kspan + jc + inc;
|
||||
} while (kk < (jc + jc));
|
||||
break;
|
||||
#endif /* FFT_RADIX4 */
|
||||
}
|
||||
}
|
||||
|
||||
/* permute the results to normal order---done in two stages */
|
||||
/* permutation for square factors of n */
|
||||
Permute_Results_Label:
|
||||
fftstate->Perm [0] = ns;
|
||||
if (kt) {
|
||||
k = kt + kt + 1;
|
||||
if (mfactor < k)
|
||||
k--;
|
||||
j = 1;
|
||||
fftstate->Perm [k] = jc;
|
||||
do {
|
||||
fftstate->Perm [j] = fftstate->Perm [j - 1] / fftstate->factor [j - 1];
|
||||
fftstate->Perm [k - 1] = fftstate->Perm [k] * fftstate->factor [j - 1];
|
||||
j++;
|
||||
k--;
|
||||
} while (j < k);
|
||||
k3 = fftstate->Perm [k];
|
||||
kspan = fftstate->Perm [1];
|
||||
kk = jc;
|
||||
k2 = kspan;
|
||||
j = 1;
|
||||
if (nPass != nTotal) {
|
||||
/* permutation for multivariate transform */
|
||||
Permute_Multi_Label:
|
||||
do {
|
||||
do {
|
||||
k = kk + jc;
|
||||
do {
|
||||
/* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */
|
||||
ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak;
|
||||
bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk;
|
||||
kk += inc;
|
||||
k2 += inc;
|
||||
} while (kk < (k-1));
|
||||
kk += ns - jc;
|
||||
k2 += ns - jc;
|
||||
} while (kk < (nt-1));
|
||||
k2 = k2 - nt + kspan;
|
||||
kk = kk - nt + jc;
|
||||
} while (k2 < (ns-1));
|
||||
do {
|
||||
do {
|
||||
k2 -= fftstate->Perm [j - 1];
|
||||
j++;
|
||||
k2 = fftstate->Perm [j] + k2;
|
||||
} while (k2 > fftstate->Perm [j - 1]);
|
||||
j = 1;
|
||||
do {
|
||||
if (kk < (k2-1))
|
||||
goto Permute_Multi_Label;
|
||||
kk += jc;
|
||||
k2 += kspan;
|
||||
} while (k2 < (ns-1));
|
||||
} while (kk < (ns-1));
|
||||
} else {
|
||||
/* permutation for single-variate transform (optional code) */
|
||||
Permute_Single_Label:
|
||||
do {
|
||||
/* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */
|
||||
ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak;
|
||||
bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk;
|
||||
kk += inc;
|
||||
k2 += kspan;
|
||||
} while (k2 < (ns-1));
|
||||
do {
|
||||
do {
|
||||
k2 -= fftstate->Perm [j - 1];
|
||||
j++;
|
||||
k2 = fftstate->Perm [j] + k2;
|
||||
} while (k2 >= fftstate->Perm [j - 1]);
|
||||
j = 1;
|
||||
do {
|
||||
if (kk < k2)
|
||||
goto Permute_Single_Label;
|
||||
kk += inc;
|
||||
k2 += kspan;
|
||||
} while (k2 < (ns-1));
|
||||
} while (kk < (ns-1));
|
||||
}
|
||||
jc = k3;
|
||||
}
|
||||
|
||||
if ((kt << 1) + 1 >= mfactor)
|
||||
return 0;
|
||||
ispan = fftstate->Perm [kt];
|
||||
/* permutation for square-free factors of n */
|
||||
j = mfactor - kt;
|
||||
fftstate->factor [j] = 1;
|
||||
do {
|
||||
fftstate->factor [j - 1] *= fftstate->factor [j];
|
||||
j--;
|
||||
} while (j != kt);
|
||||
kt++;
|
||||
nn = fftstate->factor [kt - 1] - 1;
|
||||
if (nn > (int) max_perm) {
|
||||
return -1;
|
||||
}
|
||||
j = jj = 0;
|
||||
for (;;) {
|
||||
k = kt + 1;
|
||||
k2 = fftstate->factor [kt - 1];
|
||||
kk = fftstate->factor [k - 1];
|
||||
j++;
|
||||
if (j > nn)
|
||||
break; /* exit infinite loop */
|
||||
jj += kk;
|
||||
while (jj >= k2) {
|
||||
jj -= k2;
|
||||
k2 = kk;
|
||||
k++;
|
||||
kk = fftstate->factor [k - 1];
|
||||
jj += kk;
|
||||
}
|
||||
fftstate->Perm [j - 1] = jj;
|
||||
}
|
||||
/* determine the permutation cycles of length greater than 1 */
|
||||
j = 0;
|
||||
for (;;) {
|
||||
do {
|
||||
j++;
|
||||
kk = fftstate->Perm [j - 1];
|
||||
} while (kk < 0);
|
||||
if (kk != j) {
|
||||
do {
|
||||
k = kk;
|
||||
kk = fftstate->Perm [k - 1];
|
||||
fftstate->Perm [k - 1] = -kk;
|
||||
} while (kk != j);
|
||||
k3 = kk;
|
||||
} else {
|
||||
fftstate->Perm [j - 1] = -j;
|
||||
if (j == nn)
|
||||
break; /* exit infinite loop */
|
||||
}
|
||||
}
|
||||
max_factors *= inc;
|
||||
/* reorder a and b, following the permutation cycles */
|
||||
for (;;) {
|
||||
j = k3 + 1;
|
||||
nt -= ispan;
|
||||
ii = nt - inc + 1;
|
||||
if (nt < 0)
|
||||
break; /* exit infinite loop */
|
||||
do {
|
||||
do {
|
||||
j--;
|
||||
} while (fftstate->Perm [j - 1] < 0);
|
||||
jj = jc;
|
||||
do {
|
||||
kspan = jj;
|
||||
if (jj > max_factors) {
|
||||
kspan = max_factors;
|
||||
}
|
||||
jj -= kspan;
|
||||
k = fftstate->Perm [j - 1];
|
||||
kk = jc * k + ii + jj;
|
||||
k1 = kk + kspan - 1;
|
||||
k2 = 0;
|
||||
do {
|
||||
k2++;
|
||||
Rtmp [k2 - 1] = Re [k1];
|
||||
Itmp [k2 - 1] = Im [k1];
|
||||
k1 -= inc;
|
||||
} while (k1 != (kk-1));
|
||||
do {
|
||||
k1 = kk + kspan - 1;
|
||||
k2 = k1 - jc * (k + fftstate->Perm [k - 1]);
|
||||
k = -fftstate->Perm [k - 1];
|
||||
do {
|
||||
Re [k1] = Re [k2];
|
||||
Im [k1] = Im [k2];
|
||||
k1 -= inc;
|
||||
k2 -= inc;
|
||||
} while (k1 != (kk-1));
|
||||
kk = k2 + 1;
|
||||
} while (k != j);
|
||||
k1 = kk + kspan - 1;
|
||||
k2 = 0;
|
||||
do {
|
||||
k2++;
|
||||
Re [k1] = Rtmp [k2 - 1];
|
||||
Im [k1] = Itmp [k2 - 1];
|
||||
k1 -= inc;
|
||||
} while (k1 != (kk-1));
|
||||
} while (jj);
|
||||
} while (j != 1);
|
||||
}
|
||||
return 0; /* exit point here */
|
||||
}
|
||||
/* ---------------------- end-of-file (c source) ---------------------- */
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*--------------------------------*-C-*---------------------------------*
|
||||
* File:
|
||||
* fftn.h
|
||||
* ---------------------------------------------------------------------*
|
||||
* Re[]: real value array
|
||||
* Im[]: imaginary value array
|
||||
* nTotal: total number of complex values
|
||||
* nPass: number of elements involved in this pass of transform
|
||||
* nSpan: nspan/nPass = number of bytes to increment pointer
|
||||
* in Re[] and Im[]
|
||||
* isign: exponent: +1 = forward -1 = reverse
|
||||
* scaling: normalizing constant by which the final result is *divided*
|
||||
* scaling == -1, normalize by total dimension of the transform
|
||||
* scaling < -1, normalize by the square-root of the total dimension
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
* See the comments in the code for correct usage!
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_
|
||||
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
|
||||
/* double precision routine */
|
||||
|
||||
|
||||
int WebRtcIsac_Fftns (unsigned int ndim, const int dims[], double Re[], double Im[],
|
||||
int isign, double scaling, FFTstr *fftstate);
|
||||
|
||||
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ */
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_FilterAR().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
int WebRtcSpl_FilterAR(G_CONST WebRtc_Word16* a,
|
||||
int a_length,
|
||||
G_CONST WebRtc_Word16* x,
|
||||
int x_length,
|
||||
WebRtc_Word16* state,
|
||||
int state_length,
|
||||
WebRtc_Word16* state_low,
|
||||
int state_low_length,
|
||||
WebRtc_Word16* filtered,
|
||||
WebRtc_Word16* filtered_low,
|
||||
int filtered_low_length)
|
||||
{
|
||||
WebRtc_Word32 o;
|
||||
WebRtc_Word32 oLOW;
|
||||
int i, j, stop;
|
||||
G_CONST WebRtc_Word16* x_ptr = &x[0];
|
||||
WebRtc_Word16* filteredFINAL_ptr = filtered;
|
||||
WebRtc_Word16* filteredFINAL_LOW_ptr = filtered_low;
|
||||
|
||||
for (i = 0; i < x_length; i++)
|
||||
{
|
||||
// Calculate filtered[i] and filtered_low[i]
|
||||
G_CONST WebRtc_Word16* a_ptr = &a[1];
|
||||
WebRtc_Word16* filtered_ptr = &filtered[i - 1];
|
||||
WebRtc_Word16* filtered_low_ptr = &filtered_low[i - 1];
|
||||
WebRtc_Word16* state_ptr = &state[state_length - 1];
|
||||
WebRtc_Word16* state_low_ptr = &state_low[state_length - 1];
|
||||
|
||||
o = (WebRtc_Word32)(*x_ptr++) << 12;
|
||||
oLOW = (WebRtc_Word32)0;
|
||||
|
||||
stop = (i < a_length) ? i + 1 : a_length;
|
||||
for (j = 1; j < stop; j++)
|
||||
{
|
||||
o -= WEBRTC_SPL_MUL_16_16(*a_ptr, *filtered_ptr--);
|
||||
oLOW -= WEBRTC_SPL_MUL_16_16(*a_ptr++, *filtered_low_ptr--);
|
||||
}
|
||||
for (j = i + 1; j < a_length; j++)
|
||||
{
|
||||
o -= WEBRTC_SPL_MUL_16_16(*a_ptr, *state_ptr--);
|
||||
oLOW -= WEBRTC_SPL_MUL_16_16(*a_ptr++, *state_low_ptr--);
|
||||
}
|
||||
|
||||
o += (oLOW >> 12);
|
||||
*filteredFINAL_ptr = (WebRtc_Word16)((o + (WebRtc_Word32)2048) >> 12);
|
||||
*filteredFINAL_LOW_ptr++ = (WebRtc_Word16)(o - ((WebRtc_Word32)(*filteredFINAL_ptr++)
|
||||
<< 12));
|
||||
}
|
||||
|
||||
// Save the filter state
|
||||
if (x_length >= state_length)
|
||||
{
|
||||
WebRtcSpl_CopyFromEndW16(filtered, x_length, a_length - 1, state);
|
||||
WebRtcSpl_CopyFromEndW16(filtered_low, x_length, a_length - 1, state_low);
|
||||
} else
|
||||
{
|
||||
for (i = 0; i < state_length - x_length; i++)
|
||||
{
|
||||
state[i] = state[i + x_length];
|
||||
state_low[i] = state_low[i + x_length];
|
||||
}
|
||||
for (i = 0; i < x_length; i++)
|
||||
{
|
||||
state[state_length - x_length + i] = filtered[i];
|
||||
state[state_length - x_length + i] = filtered_low[i];
|
||||
}
|
||||
}
|
||||
|
||||
return x_length;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_FilterARFastQ12().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_FilterARFastQ12(WebRtc_Word16 *in, WebRtc_Word16 *out, WebRtc_Word16 *A,
|
||||
WebRtc_Word16 A_length, WebRtc_Word16 length)
|
||||
{
|
||||
WebRtc_Word32 o;
|
||||
int i, j;
|
||||
|
||||
WebRtc_Word16 *x_ptr = &in[0];
|
||||
WebRtc_Word16 *filtered_ptr = &out[0];
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
// Calculate filtered[i]
|
||||
G_CONST WebRtc_Word16 *a_ptr = &A[0];
|
||||
WebRtc_Word16 *state_ptr = &out[i - 1];
|
||||
|
||||
o = WEBRTC_SPL_MUL_16_16(*x_ptr++, *a_ptr++);
|
||||
|
||||
for (j = 1; j < A_length; j++)
|
||||
{
|
||||
o -= WEBRTC_SPL_MUL_16_16(*a_ptr++,*state_ptr--);
|
||||
}
|
||||
|
||||
// Saturate the output
|
||||
o = WEBRTC_SPL_SAT((WebRtc_Word32)134215679, o, (WebRtc_Word32)-134217728);
|
||||
|
||||
*filtered_ptr++ = (WebRtc_Word16)((o + (WebRtc_Word32)2048) >> 12);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <memory.h>
|
||||
#ifdef WEBRTC_ANDROID
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "pitch_estimator.h"
|
||||
#include "lpc_analysis.h"
|
||||
#include "codec.h"
|
||||
|
||||
|
||||
|
||||
void WebRtcIsac_AllPoleFilter(double *InOut, double *Coef, int lengthInOut, int orderCoef){
|
||||
|
||||
/* the state of filter is assumed to be in InOut[-1] to InOut[-orderCoef] */
|
||||
double scal;
|
||||
double sum;
|
||||
int n,k;
|
||||
|
||||
//if (fabs(Coef[0]-1.0)<0.001) {
|
||||
if ( (Coef[0] > 0.9999) && (Coef[0] < 1.0001) )
|
||||
{
|
||||
for(n = 0; n < lengthInOut; n++)
|
||||
{
|
||||
sum = Coef[1] * InOut[-1];
|
||||
for(k = 2; k <= orderCoef; k++){
|
||||
sum += Coef[k] * InOut[-k];
|
||||
}
|
||||
*InOut++ -= sum;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scal = 1.0 / Coef[0];
|
||||
for(n=0;n<lengthInOut;n++)
|
||||
{
|
||||
*InOut *= scal;
|
||||
for(k=1;k<=orderCoef;k++){
|
||||
*InOut -= scal*Coef[k]*InOut[-k];
|
||||
}
|
||||
InOut++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_AllZeroFilter(double *In, double *Coef, int lengthInOut, int orderCoef, double *Out){
|
||||
|
||||
/* the state of filter is assumed to be in In[-1] to In[-orderCoef] */
|
||||
|
||||
int n, k;
|
||||
double tmp;
|
||||
|
||||
for(n = 0; n < lengthInOut; n++)
|
||||
{
|
||||
tmp = In[0] * Coef[0];
|
||||
|
||||
for(k = 1; k <= orderCoef; k++){
|
||||
tmp += Coef[k] * In[-k];
|
||||
}
|
||||
|
||||
*Out++ = tmp;
|
||||
In++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WebRtcIsac_ZeroPoleFilter(double *In, double *ZeroCoef, double *PoleCoef, int lengthInOut, int orderCoef, double *Out){
|
||||
|
||||
/* the state of the zero section is assumed to be in In[-1] to In[-orderCoef] */
|
||||
/* the state of the pole section is assumed to be in Out[-1] to Out[-orderCoef] */
|
||||
|
||||
WebRtcIsac_AllZeroFilter(In,ZeroCoef,lengthInOut,orderCoef,Out);
|
||||
WebRtcIsac_AllPoleFilter(Out,PoleCoef,lengthInOut,orderCoef);
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_AutoCorr(
|
||||
double *r,
|
||||
const double *x,
|
||||
int N,
|
||||
int order
|
||||
)
|
||||
{
|
||||
int lag, n;
|
||||
double sum, prod;
|
||||
const double *x_lag;
|
||||
|
||||
for (lag = 0; lag <= order; lag++)
|
||||
{
|
||||
sum = 0.0f;
|
||||
x_lag = &x[lag];
|
||||
prod = x[0] * x_lag[0];
|
||||
for (n = 1; n < N - lag; n++) {
|
||||
sum += prod;
|
||||
prod = x[n] * x_lag[n];
|
||||
}
|
||||
sum += prod;
|
||||
r[lag] = sum;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_BwExpand(double *out, double *in, double coef, short length) {
|
||||
int i;
|
||||
double chirp;
|
||||
|
||||
chirp = coef;
|
||||
|
||||
out[0] = in[0];
|
||||
for (i = 1; i < length; i++) {
|
||||
out[i] = chirp * in[i];
|
||||
chirp *= coef;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcIsac_WeightingFilter(const double *in, double *weiout, double *whiout, WeightFiltstr *wfdata) {
|
||||
|
||||
double tmpbuffer[PITCH_FRAME_LEN + PITCH_WLPCBUFLEN];
|
||||
double corr[PITCH_WLPCORDER+1], rc[PITCH_WLPCORDER+1];
|
||||
double apol[PITCH_WLPCORDER+1], apolr[PITCH_WLPCORDER+1];
|
||||
double rho=0.9, *inp, *dp, *dp2;
|
||||
double whoutbuf[PITCH_WLPCBUFLEN + PITCH_WLPCORDER];
|
||||
double weoutbuf[PITCH_WLPCBUFLEN + PITCH_WLPCORDER];
|
||||
double *weo, *who, opol[PITCH_WLPCORDER+1], ext[PITCH_WLPCWINLEN];
|
||||
int k, n, endpos, start;
|
||||
|
||||
/* Set up buffer and states */
|
||||
memcpy(tmpbuffer, wfdata->buffer, sizeof(double) * PITCH_WLPCBUFLEN);
|
||||
memcpy(tmpbuffer+PITCH_WLPCBUFLEN, in, sizeof(double) * PITCH_FRAME_LEN);
|
||||
memcpy(wfdata->buffer, tmpbuffer+PITCH_FRAME_LEN, sizeof(double) * PITCH_WLPCBUFLEN);
|
||||
|
||||
dp=weoutbuf;
|
||||
dp2=whoutbuf;
|
||||
for (k=0;k<PITCH_WLPCORDER;k++) {
|
||||
*dp++ = wfdata->weostate[k];
|
||||
*dp2++ = wfdata->whostate[k];
|
||||
opol[k]=0.0;
|
||||
}
|
||||
opol[0]=1.0;
|
||||
opol[PITCH_WLPCORDER]=0.0;
|
||||
weo=dp;
|
||||
who=dp2;
|
||||
|
||||
endpos=PITCH_WLPCBUFLEN + PITCH_SUBFRAME_LEN;
|
||||
inp=tmpbuffer + PITCH_WLPCBUFLEN;
|
||||
|
||||
for (n=0; n<PITCH_SUBFRAMES; n++) {
|
||||
/* Windowing */
|
||||
start=endpos-PITCH_WLPCWINLEN;
|
||||
for (k=0; k<PITCH_WLPCWINLEN; k++) {
|
||||
ext[k]=wfdata->window[k]*tmpbuffer[start+k];
|
||||
}
|
||||
|
||||
/* Get LPC polynomial */
|
||||
WebRtcIsac_AutoCorr(corr, ext, PITCH_WLPCWINLEN, PITCH_WLPCORDER);
|
||||
corr[0]=1.01*corr[0]+1.0; /* White noise correction */
|
||||
WebRtcIsac_LevDurb(apol, rc, corr, PITCH_WLPCORDER);
|
||||
WebRtcIsac_BwExpand(apolr, apol, rho, PITCH_WLPCORDER+1);
|
||||
|
||||
/* Filtering */
|
||||
WebRtcIsac_ZeroPoleFilter(inp, apol, apolr, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, weo);
|
||||
WebRtcIsac_ZeroPoleFilter(inp, apolr, opol, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, who);
|
||||
|
||||
inp+=PITCH_SUBFRAME_LEN;
|
||||
endpos+=PITCH_SUBFRAME_LEN;
|
||||
weo+=PITCH_SUBFRAME_LEN;
|
||||
who+=PITCH_SUBFRAME_LEN;
|
||||
}
|
||||
|
||||
/* Export filter states */
|
||||
for (k=0;k<PITCH_WLPCORDER;k++) {
|
||||
wfdata->weostate[k]=weoutbuf[PITCH_FRAME_LEN+k];
|
||||
wfdata->whostate[k]=whoutbuf[PITCH_FRAME_LEN+k];
|
||||
}
|
||||
|
||||
/* Export output data */
|
||||
memcpy(weiout, weoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
|
||||
memcpy(whiout, whoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
|
||||
}
|
||||
|
||||
|
||||
static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826};
|
||||
static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744};
|
||||
|
||||
|
||||
|
||||
void WebRtcIsac_AllpassFilterForDec(double *InOut,
|
||||
const double *APSectionFactors,
|
||||
int lengthInOut,
|
||||
double *FilterState)
|
||||
{
|
||||
//This performs all-pass filtering--a series of first order all-pass sections are used
|
||||
//to filter the input in a cascade manner.
|
||||
int n,j;
|
||||
double temp;
|
||||
for (j=0; j<ALLPASSSECTIONS; j++){
|
||||
for (n=0;n<lengthInOut;n+=2){
|
||||
temp = InOut[n]; //store input
|
||||
InOut[n] = FilterState[j] + APSectionFactors[j]*temp;
|
||||
FilterState[j] = -APSectionFactors[j]*InOut[n] + temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcIsac_DecimateAllpass(const double *in,
|
||||
double *state_in, /* array of size: 2*ALLPASSSECTIONS+1 */
|
||||
int N, /* number of input samples */
|
||||
double *out) /* array of size N/2 */
|
||||
{
|
||||
int n;
|
||||
double data_vec[PITCH_FRAME_LEN];
|
||||
|
||||
/* copy input */
|
||||
memcpy(data_vec+1, in, sizeof(double) * (N-1));
|
||||
|
||||
data_vec[0] = state_in[2*ALLPASSSECTIONS]; //the z^(-1) state
|
||||
state_in[2*ALLPASSSECTIONS] = in[N-1];
|
||||
|
||||
WebRtcIsac_AllpassFilterForDec(data_vec+1, APupper, N, state_in);
|
||||
WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N, state_in+ALLPASSSECTIONS);
|
||||
|
||||
for (n=0;n<N/2;n++)
|
||||
out[n] = data_vec[2*n] + data_vec[2*n+1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* create high-pass filter ocefficients
|
||||
* z = 0.998 * exp(j*2*pi*35/8000);
|
||||
* p = 0.94 * exp(j*2*pi*140/8000);
|
||||
* HP_b = [1, -2*real(z), abs(z)^2];
|
||||
* HP_a = [1, -2*real(p), abs(p)^2]; */
|
||||
static const double a_coef[2] = { 1.86864659625574, -0.88360000000000};
|
||||
static const double b_coef[2] = {-1.99524591718270, 0.99600400000000};
|
||||
static const float a_coef_float[2] = { 1.86864659625574f, -0.88360000000000f};
|
||||
static const float b_coef_float[2] = {-1.99524591718270f, 0.99600400000000f};
|
||||
|
||||
/* second order high-pass filter */
|
||||
void WebRtcIsac_Highpass(const double *in, double *out, double *state, int N)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k=0; k<N; k++) {
|
||||
*out = *in + state[1];
|
||||
state[1] = state[0] + b_coef[0] * *in + a_coef[0] * *out;
|
||||
state[0] = b_coef[1] * *in++ + a_coef[1] * *out++;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcIsac_Highpass_float(const float *in, double *out, double *state, int N)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k=0; k<N; k++) {
|
||||
*out = (double)*in + state[1];
|
||||
state[1] = state[0] + b_coef_float[0] * *in + a_coef_float[0] * *out;
|
||||
state[0] = b_coef_float[1] * (double)*in++ + a_coef_float[1] * *out++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_FilterMAFastQ12().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_FilterMAFastQ12(WebRtc_Word16* in_ptr,
|
||||
WebRtc_Word16* out_ptr,
|
||||
WebRtc_Word16* B,
|
||||
WebRtc_Word16 B_length,
|
||||
WebRtc_Word16 length)
|
||||
{
|
||||
WebRtc_Word32 o;
|
||||
int i, j;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
G_CONST WebRtc_Word16* b_ptr = &B[0];
|
||||
G_CONST WebRtc_Word16* x_ptr = &in_ptr[i];
|
||||
|
||||
o = (WebRtc_Word32)0;
|
||||
|
||||
for (j = 0; j < B_length; j++)
|
||||
{
|
||||
o += WEBRTC_SPL_MUL_16_16(*b_ptr++, *x_ptr--);
|
||||
}
|
||||
|
||||
// If output is higher than 32768, saturate it. Same with negative side
|
||||
// 2^27 = 134217728, which corresponds to 32768 in Q12
|
||||
|
||||
// Saturate the output
|
||||
o = WEBRTC_SPL_SAT((WebRtc_Word32)134215679, o, (WebRtc_Word32)-134217728);
|
||||
|
||||
*out_ptr++ = (WebRtc_Word16)((o + (WebRtc_Word32)2048) >> 12);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* filterbank_tables.c*/
|
||||
/* This file contains variables that are used in filterbanks.c*/
|
||||
|
||||
#include "filterbank_tables.h"
|
||||
#include "settings.h"
|
||||
|
||||
/* The composite all-pass filter factors */
|
||||
const float WebRtcIsac_kCompositeApFactorsFloat[4] = {
|
||||
0.03470000000000f, 0.15440000000000f, 0.38260000000000f, 0.74400000000000f};
|
||||
|
||||
/* The upper channel all-pass filter factors */
|
||||
const float WebRtcIsac_kUpperApFactorsFloat[2] = {
|
||||
0.03470000000000f, 0.38260000000000f};
|
||||
|
||||
/* The lower channel all-pass filter factors */
|
||||
const float WebRtcIsac_kLowerApFactorsFloat[2] = {
|
||||
0.15440000000000f, 0.74400000000000f};
|
||||
|
||||
/* The matrix for transforming the backward composite state to upper channel state */
|
||||
const float WebRtcIsac_kTransform1Float[8] = {
|
||||
-0.00158678506084f, 0.00127157815343f, -0.00104805672709f, 0.00084837248079f,
|
||||
0.00134467983258f, -0.00107756549387f, 0.00088814793277f, -0.00071893072525f};
|
||||
|
||||
/* The matrix for transforming the backward composite state to lower channel state */
|
||||
const float WebRtcIsac_kTransform2Float[8] = {
|
||||
-0.00170686041697f, 0.00136780109829f, -0.00112736532350f, 0.00091257055385f,
|
||||
0.00103094281812f, -0.00082615076557f, 0.00068092756088f, -0.00055119165484f};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user