[asterisk-commits] russell: branch russell/indications r174365 - in /team/russell/indications: a...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Feb 9 17:56:13 CST 2009


Author: russell
Date: Mon Feb  9 17:56:13 2009
New Revision: 174365

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=174365
Log:
Commit progress on re-work of indications API - abotu 85% done

I'll type up more of a description when I'm more awake, but it includes cool
things like not crashing if you do a reload with changes in the configuration
for indications currently in use.

Removed:
    team/russell/indications/res/res_indications.c
Modified:
    team/russell/indications/apps/app_disa.c
    team/russell/indications/apps/app_read.c
    team/russell/indications/apps/app_readexten.c
    team/russell/indications/channels/chan_skinny.c
    team/russell/indications/channels/chan_unistim.c
    team/russell/indications/configs/indications.conf.sample
    team/russell/indications/funcs/func_channel.c
    team/russell/indications/include/asterisk/_private.h
    team/russell/indications/include/asterisk/channel.h
    team/russell/indications/include/asterisk/indications.h
    team/russell/indications/main/app.c
    team/russell/indications/main/asterisk.c
    team/russell/indications/main/channel.c
    team/russell/indications/main/indications.c
    team/russell/indications/main/loader.c
    team/russell/indications/main/pbx.c
    team/russell/indications/res/snmp/agent.c

Modified: team/russell/indications/apps/app_disa.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/apps/app_disa.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/apps/app_disa.c (original)
+++ team/russell/indications/apps/app_disa.c Mon Feb  9 17:56:13 2009
@@ -124,15 +124,19 @@
 
 static void play_dialtone(struct ast_channel *chan, char *mailbox)
 {
-	const struct tone_zone_sound *ts = NULL;
-	if(ast_app_has_voicemail(mailbox, NULL))
+	const struct ast_tone_zone_sound *ts = NULL;
+
+	if (ast_app_has_voicemail(mailbox, NULL)) {
 		ts = ast_get_indication_tone(chan->zone, "dialrecall");
-	else
+	} else {
 		ts = ast_get_indication_tone(chan->zone, "dial");
-	if (ts)
+	}
+
+	if (ts) {
 		ast_playtones_start(chan, 0, ts->data, 0);
-	else
+	} else {
 		ast_tonepair_start(chan, 350, 440, 0, 0);
+	}
 }
 
 static int disa_exec(struct ast_channel *chan, void *data)

Modified: team/russell/indications/apps/app_read.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/apps/app_read.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/apps/app_read.c (original)
+++ team/russell/indications/apps/app_read.c Mon Feb  9 17:56:13 2009
@@ -132,7 +132,7 @@
 	int tries = 1, to = 0, x = 0;
 	double tosec;
 	char *argcopy = NULL;
-	struct tone_zone_sound *ts = NULL;
+	struct ast_tone_zone_sound *ts = NULL;
 	struct ast_flags flags = {0};
 	const char *status = "ERROR";
 

Modified: team/russell/indications/apps/app_readexten.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/apps/app_readexten.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/apps/app_readexten.c (original)
+++ team/russell/indications/apps/app_readexten.c Mon Feb  9 17:56:13 2009
@@ -132,7 +132,7 @@
 	int maxdigits = sizeof(exten) - 1;
 	int timeout = 0, digit_timeout = 0, x = 0;
 	char *argcopy = NULL, *status = "";
-	struct tone_zone_sound *ts = NULL;
+	struct ast_tone_zone_sound *ts = NULL;
 	struct ast_flags flags = {0};
 
 	 AST_DECLARE_APP_ARGS(arglist,
@@ -179,8 +179,9 @@
 	if (digit_timeout <= 0)
 		digit_timeout = chan->pbx ? chan->pbx->dtimeoutms : 5000;
 
-	if (ast_test_flag(&flags, OPT_INDICATION) && !ast_strlen_zero(arglist.filename))
+	if (ast_test_flag(&flags, OPT_INDICATION) && !ast_strlen_zero(arglist.filename)) {
 		ts = ast_get_indication_tone(chan->zone, arglist.filename);
+	}
 
 	do {
 		if (chan->_state != AST_STATE_UP) {

Modified: team/russell/indications/channels/chan_skinny.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/channels/chan_skinny.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/channels/chan_skinny.c (original)
+++ team/russell/indications/channels/chan_skinny.c Mon Feb  9 17:56:13 2009
@@ -3751,7 +3751,7 @@
 {
 	struct skinny_subchannel *xferor; /* the sub doing the transferring */
 	struct skinny_subchannel *xferee; /* the sub being transferred */
-	const struct tone_zone_sound *ts = NULL;
+	const struct ast_tone_zone_sound *ts = NULL;
 		
 	if (ast_bridged_channel(sub->owner) || ast_bridged_channel(sub->related->owner)) {
 		if (sub->xferor) {

Modified: team/russell/indications/channels/chan_unistim.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/channels/chan_unistim.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/channels/chan_unistim.c (original)
+++ team/russell/indications/channels/chan_unistim.c Mon Feb  9 17:56:13 2009
@@ -439,7 +439,7 @@
 	char datetimeformat;	    /*!< format used for displaying time/date */
 	char contrast;			  /*!< contrast */
 	char country[3];			/*!< country used for dial tone frequency */
-	struct tone_zone *tz;	       /*!< Tone zone for res_indications (ring, busy, congestion) */
+	struct ast_tone_zone *tz;	       /*!< Tone zone for res_indications (ring, busy, congestion) */
 	char ringvolume;			/*!< Ring volume */
 	char ringstyle;			 /*!< Ring melody */
 	int rtp_port;			   /*!< RTP port used by the phone */
@@ -4057,17 +4057,16 @@
 	return "UNKNOWN";
 }
 
-static void in_band_indication(struct ast_channel *ast, const struct tone_zone *tz,
+static void in_band_indication(struct ast_channel *ast, const struct ast_tone_zone *tz,
 	const char *indication)
 {
-	const struct tone_zone_sound *ts = NULL;
-
-	ts = ast_get_indication_tone(tz, indication);
-
-	if (ts && ts->data[0])
+	const struct ast_tone_zone_sound *ts = NULL;
+
+	if ((ts = ast_get_indication_tone(tz, indication))) {
 		ast_playtones_start(ast, 0, ts->data, 1);
-	else
+	} else {
 		ast_log(LOG_WARNING, "Unable to get indication tone for %s\n", indication);
+	}
 }
 
 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data, 

Modified: team/russell/indications/configs/indications.conf.sample
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/configs/indications.conf.sample?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/configs/indications.conf.sample (original)
+++ team/russell/indications/configs/indications.conf.sample Mon Feb  9 17:56:13 2009
@@ -17,9 +17,6 @@
 ; [example]
 ; description = string
 ;      The full name of your country, in English.
-; alias = iso[,iso]*
-;      List of other countries 2-letter iso codes, which have the same
-;      tone indications.
 ; ringcadence = num[,num]*
 ;      List of durations the physical bell rings.
 ; dial = tonelist

Modified: team/russell/indications/funcs/func_channel.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/funcs/func_channel.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/funcs/func_channel.c (original)
+++ team/russell/indications/funcs/func_channel.c Mon Feb  9 17:56:13 2009
@@ -296,12 +296,19 @@
 	}
 #endif
 	else if (!strcasecmp(data, "tonezone")) {
-		struct tone_zone *new_zone;
+		struct ast_tone_zone *new_zone;
 		if (!(new_zone = ast_get_indication_zone(value))) {
 			ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
 			ret = -1;	
-		} else 
-			chan->zone = new_zone;
+		} else {
+			ast_channel_lock(chan);
+			if (chan->zone) {
+				chan->zone = ast_tone_zone_unref(chan->zone);
+			}
+			chan->zone = ast_tone_zone_ref(new_zone);
+			ast_channel_unlock(chan);
+			new_zone = ast_tone_zone_unref(new_zone);
+		}
 	} else if (!strcasecmp(data, "callgroup"))
 		chan->callgroup = ast_get_group(value);
 	else if (!strcasecmp(data, "txgain")) {

Modified: team/russell/indications/include/asterisk/_private.h
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/include/asterisk/_private.h?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/include/asterisk/_private.h (original)
+++ team/russell/indications/include/asterisk/_private.h Mon Feb  9 17:56:13 2009
@@ -39,6 +39,8 @@
 int ast_http_reload(void);		/*!< Provided by http.c */
 int ast_tps_init(void); 		/*!< Provided by taskprocessor.c */
 int ast_timing_init(void);		/*!< Provided by timing.c */
+int ast_indications_init(void); /*!< Provided by indications.c */
+int ast_indications_reload(void);/*!< Provided by indications.c */
 
 /*!
  * \brief Reload asterisk modules.

Modified: team/russell/indications/include/asterisk/channel.h
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/include/asterisk/channel.h?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/include/asterisk/channel.h (original)
+++ team/russell/indications/include/asterisk/channel.h Mon Feb  9 17:56:13 2009
@@ -424,7 +424,7 @@
 	struct ast_trans_pvt *readtrans;		/*!< Read translation path */
 	struct ast_audiohook_list *audiohooks;
 	struct ast_cdr *cdr;				/*!< Call Detail Record */
-	struct tone_zone *zone;			/*!< Tone zone as set in indications.conf or
+	struct ast_tone_zone *zone;			/*!< Tone zone as set in indications.conf or
 							     in the CHANNEL dialplan function */
 	struct ast_channel_monitor *monitor;		/*!< Channel monitoring */
 #ifdef HAVE_EPOLL

Modified: team/russell/indications/include/asterisk/indications.h
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/include/asterisk/indications.h?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/include/asterisk/indications.h (original)
+++ team/russell/indications/include/asterisk/indications.h Mon Feb  9 17:56:13 2009
@@ -1,91 +1,78 @@
 /*
  * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2002, Pauline Middelink
+ * Copyright (C) 2009, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
  * any of the maintainers of this project for assistance;
  * the project provides a web site, mailing lists and IRC
  * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
  */
 
-/*! \file
- * \brief BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+/*!
+ * \file
+ * \brief Tone Indication Support
  *
- * Primary Author: Pauline Middelink <middelink at polyware.nl>
- *
+ * \author Pauline Middelink <middelink at polyware.nl>
+ * \author Russell Bryant <russell at digium.com>
  */
 
 #ifndef _ASTERISK_INDICATIONS_H
 #define _ASTERISK_INDICATIONS_H
 
-#include "asterisk/lock.h"
+#include "asterisk/astobj2.h"
 
-/*! \brief Description is a series of tones of the format:
-	   [!]freq1[+freq2][/duration] separated by commas.  There
-	   are no spaces.  The sequence is repeated back to the 
-	   first tone description not preceeded by !. Duration is
-	   specified in milliseconds */
-struct tone_zone_sound {
-	const char *name;			/*!< Identifing name */
-	const char *data;			/*!< Actual zone description */
-	AST_LIST_ENTRY(tone_zone_sound) list;
+/*!
+ * \brief Description of a tone
+ *
+ * Description is a series of tones of the format:
+ * [!]freq1[+freq2][/duration] separated by commas.  There
+ * are no spaces.  The sequence is repeated back to the
+ * first tone description not preceeded by !. Duration is
+ * specified in milliseconds
+ */
+struct ast_tone_zone_sound {
+	const char *name;   /*!< Identifying name */
+	const char *data;   /*!< Actual zone description */
+	AST_LIST_ENTRY(ast_tone_zone_sound) entry;
 };
 
-struct tone_zone {
-	AST_RWLIST_ENTRY(tone_zone) list;
-	char country[5];				/*!< Country code */
-	char alias[5];					/*!< is this an alias? */
-	char description[40];				/*!< Description */
-	int  nrringcadence;				/*!< # registered ringcadence elements */
-	int *ringcadence;				/*!< Ring cadence */
-	AST_LIST_HEAD_NOLOCK(, tone_zone_sound) tones;		/*!< The known tones for this zone */
+struct ast_tone_zone {
+	char country[5];         /*!< Country code */
+	char description[40];    /*!< Description */
+	int  nrringcadence;      /*!< # registered ringcadence elements */
+	int *ringcadence;        /*!< Ring cadence */
+	AST_LIST_HEAD_NOLOCK(, ast_tone_zone_sound) tones;		/*!< The known tones for this zone */
 };
 
-/*! \brief set the default tone country */
-int ast_set_indication_country(const char *country);
+/*!
+ * \brief locate ast_tone_zone
+ *
+ * \param county country to find, if== NULL, get the default country
+ */
+struct ast_tone_zone *ast_get_indication_zone(const char *country);
 
-/*! \brief locate tone_zone, given the country. if country == NULL, use the default country */
-struct tone_zone *ast_get_indication_zone(const char *country);
-/*! \brief locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */
-struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication);
-/*! \brief deallocate the passed tone zone */
-void ast_destroy_indication_zone(struct tone_zone *zone);
-
-/*! \brief add a new country, if country exists, it will be replaced. */
-int ast_register_indication_country(struct tone_zone *country);
-/*! \brief remove an existing country and all its indications, country must exist */
-int ast_unregister_indication_country(const char *country);
-/*! \brief add a new indication to a tone_zone. tone_zone must exist. if the indication already
- * exists, it will be replaced. */
-int ast_register_indication(struct tone_zone *zone, const char *indication, const char *tonelist);
-/*! \brief remove an existing tone_zone's indication. tone_zone must exist */
-int ast_unregister_indication(struct tone_zone *zone, const char *indication);
+/*! \brief locate a ast_tone_zone_sound, given the ast_tone_zone. if ast_tone_zone == NULL, use the default ast_tone_zone */
+struct ast_tone_zone_sound *ast_get_indication_tone(const struct ast_tone_zone *zone, const char *indication);
 
 /*! \brief Start a tone-list going */
 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
+
 /*! \brief Stop the tones from playing */
 void ast_playtones_stop(struct ast_channel *chan);
 
-/*! \brief support for walking through a list of indications */
-struct tone_zone *ast_walk_indications(const struct tone_zone *cur);
+struct ao2_iterator ast_tone_zone_iterator_init(void);
 
-#if 0
-extern struct tone_zone *tone_zones;
-extern ast_mutex_t tzlock;
-#endif
+#define ast_tone_zone_lock(tz) ao2_lock(tz)
+#define ast_tone_zone_unlock(tz) ao2_unlock(tz)
+#define ast_tone_zone_trylock(tz) ao2_trylock(tz)
+#define ast_tone_zone_unref(tz) ({ ao2_ref(tz, -1); (NULL); })
+#define ast_tone_zone_ref(tz) ({ ao2_ref(tz, +1); (tz); })
 
 #endif /* _ASTERISK_INDICATIONS_H */

Modified: team/russell/indications/main/app.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/main/app.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/main/app.c (original)
+++ team/russell/indications/main/app.c Mon Feb  9 17:56:13 2009
@@ -75,21 +75,23 @@
 */
 int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout) 
 {
-	struct tone_zone_sound *ts;
+	struct ast_tone_zone_sound *ts;
 	int res = 0, x = 0;
 
 	if (maxlen > size)
 		maxlen = size;
 	
-	if (!timeout && chan->pbx)
+	if (!timeout && chan->pbx) {
 		timeout = chan->pbx->dtimeoutms / 1000.0;
-	else if (!timeout)
+	} else if (!timeout) {
 		timeout = 5;
-
-	if ((ts = ast_get_indication_tone(chan->zone, "dial")) && ts->data[0])
+	}
+
+	if ((ts = ast_get_indication_tone(chan->zone, "dial")) && !ast_strlen_zero(ts->data)) {
 		res = ast_playtones_start(chan, 0, ts->data, 0);
-	else 
+	} else {
 		ast_log(LOG_NOTICE, "Huh....? no dial for indications?\n");
+	}
 	
 	for (x = strlen(collect); x < maxlen; ) {
 		res = ast_waitfordigit(chan, timeout);

Modified: team/russell/indications/main/asterisk.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/main/asterisk.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/main/asterisk.c (original)
+++ team/russell/indications/main/asterisk.c Mon Feb  9 17:56:13 2009
@@ -3583,6 +3583,11 @@
 		exit(1);
 	}
 
+	if (ast_indications_init()) {
+		printf("%s", term_quit());
+		exit(1);
+	}
+
 	if (load_modules(0)) {
 		printf("%s", term_quit());
 		exit(1);

Modified: team/russell/indications/main/channel.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/main/channel.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/main/channel.c (original)
+++ team/russell/indications/main/channel.c Mon Feb  9 17:56:13 2009
@@ -1403,7 +1403,11 @@
 		ast_cdr_discard(chan->cdr);
 		chan->cdr = NULL;
 	}
-	
+
+	if (chan->zone) {
+		chan->zone = ast_tone_zone_unref(chan->zone);
+	}
+
 	ast_mutex_destroy(&chan->lock_dont_use);
 
 	ast_string_field_free_memory(chan);
@@ -2899,7 +2903,7 @@
 	/* By using an enum, we'll get compiler warnings for values not handled 
 	 * in switch statements. */
 	enum ast_control_frame_type condition = _condition;
-	const struct tone_zone_sound *ts = NULL;
+	const struct ast_tone_zone_sound *ts = NULL;
 	int res = -1;
 
 	ast_channel_lock(chan);

Modified: team/russell/indications/main/indications.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/main/indications.c?view=diff&rev=174365&r1=174364&r2=174365
==============================================================================
--- team/russell/indications/main/indications.c (original)
+++ team/russell/indications/main/indications.c Mon Feb  9 17:56:13 2009
@@ -2,7 +2,7 @@
  * Asterisk -- An open source telephony toolkit.
  *
  * Copyright (C) 2002, Pauline Middelink
- *
+ * Copyright (C) 2009, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -15,17 +15,23 @@
  * at the top of the source tree.
  */
 
-/*! \file
+/*!
+ * \file
+ * \brief Indication Tone Handling
  *
- * \brief Tone Management
- * 
  * \author Pauline Middelink <middelink at polyware.nl>
- *
- * This set of function allow us to play a list of tones on a channel.
- * Each element has two frequencies, which are mixed together and a
- * duration. For silence both frequencies can be set to 0.
- * The playtones can be given as a comma separated string.
- *
+ * \author Russell Bryant <russell at digium.com>
+ */
+
+/*
+ * XXX TODO
+ *  - API documentation
+ *  - finish re-write of config parsing
+ *  - re-use an object for a country if it already exists when loading config
+ *  - fix users of the API to account for ref count (only chan_unistim left)
+ *  - Integrate work to pull out tone parsing into an API
+ *  - change the code such that tone definitions are only parsed once
+ *    instead of every time they are used.
  */
 
 #include "asterisk.h"
@@ -40,22 +46,74 @@
 #include "asterisk/frame.h"
 #include "asterisk/channel.h"
 #include "asterisk/utils.h"
-
-static int midi_tohz[128] = {
-			8,8,9,9,10,10,11,12,12,13,14,
-			15,16,17,18,19,20,21,23,24,25,
-			27,29,30,32,34,36,38,41,43,46,
-			48,51,55,58,61,65,69,73,77,82,
-			87,92,97,103,110,116,123,130,138,146,
-			155,164,174,184,195,207,220,233,246,261,
-			277,293,311,329,349,369,391,415,440,466,
-			493,523,554,587,622,659,698,739,783,830,
-			880,932,987,1046,1108,1174,1244,1318,1396,1479,
-			1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,
-			2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,
-			4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,
-			8869,9397,9956,10548,11175,11839,12543
-			};
+#include "asterisk/cli.h"
+#include "asterisk/module.h"
+#include "asterisk/astobj2.h"
+
+#include "asterisk/_private.h" /* _init(), _reload() */
+
+/*** DOCUMENTATION
+	<application name="PlayTones" language="en_US">
+		<synopsis>
+			Play a tone list.
+		</synopsis>
+		<syntax>
+			<parameter name="arg" required="true">
+				<para>Arg is either the tone name defined in the <filename>indications.conf</filename>
+				configuration file, or a directly specified list of frequencies and durations.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Plays a tone list. Execution will continue with the next step immediately,
+			while the tones continue to play.</para>
+			<para>See the sample <filename>indications.conf</filename> for a description of the
+			specification of a tonelist.</para>
+		</description>
+		<see-also>
+			<ref type="application">StopPlayTones</ref>
+		</see-also>
+	</application>
+	<application name="StopPlayTones" language="en_US">
+		<synopsis>
+			Stop playing a tone list.
+		</synopsis>
+		<syntax />
+		<description>
+			<para>Stop playing a tone list, initiated by PlayTones().</para>
+		</description>
+		<see-also>
+			<ref type="application">PlayTones</ref>
+		</see-also>
+	</application>
+ ***/
+
+/* Globals */
+static const char config[] = "indications.conf";
+
+static const int midi_tohz[128] = {
+	8,     8,     9,     9,     10,    10,    11,    12,    12,    13,
+	14,    15,    16,    17,    18,    19,    20,    21,    23,    24,
+	25,    27,    29,    30,    32,    34,    36,    38,    41,    43,
+	46,    48,    51,    55,    58,    61,    65,    69,    73,    77,
+	82,    87,    92,    97,    103,   110,   116,   123,   130,   138,
+	146,   155,   164,   174,   184,   195,   207,   220,   233,   246,
+	261,   277,   293,   311,   329,   349,   369,   391,   415,   440,
+	466,   493,   523,   554,   587,   622,   659,   698,   739,   783,
+	830,   880,   932,   987,   1046,  1108,  1174,  1244,  1318,  1396,
+	1479,  1567,  1661,  1760,  1864,  1975,  2093,  2217,  2349,  2489,
+	2637,  2793,  2959,  3135,  3322,  3520,  3729,  3951,  4186,  4434,
+	4698,  4978,  5274,  5587,  5919,  6271,  6644,  7040,  7458,  7902,
+	8372,  8869,  9397,  9956,  10548, 11175, 11839, 12543
+};
+
+static struct ao2_container *ast_tone_zones;
+
+#define NUM_TONE_ZONE_BUCKETS 53
+
+/*!
+ * \note Access to this is protected by locking the ast_tone_zones container
+ */
+static struct ast_tone_zone *default_tone_zone;
 
 struct playtones_item {
 	int fac1;
@@ -100,21 +158,26 @@
 {
 	struct playtones_state *ps = params;
 
-	if (chan)
+	if (chan) {
 		ast_set_write_format(chan, ps->origwfmt);
-	if (ps->items)
+	}
+
+	if (ps->items) {
 		ast_free(ps->items);
+		ps->items = NULL;
+	}
 
 	ast_free(ps);
 }
 
-static void * playtones_alloc(struct ast_channel *chan, void *params)
+static void *playtones_alloc(struct ast_channel *chan, void *params)
 {
 	struct playtones_def *pd = params;
 	struct playtones_state *ps = NULL;
 
-	if (!(ps = ast_calloc(1, sizeof(*ps))))
+	if (!(ps = ast_calloc(1, sizeof(*ps)))) {
 		return NULL;
+	}
 
 	ps->origwfmt = chan->writeformat;
 
@@ -131,10 +194,11 @@
 	}
 
 	/* Let interrupts interrupt :) */
-	if (pd->interruptible)
+	if (pd->interruptible) {
 		ast_set_flag(chan, AST_FLAG_WRITE_INT);
-	else
+	} else {
 		ast_clear_flag(chan, AST_FLAG_WRITE_INT);
+	}
 
 	return ps;
 }
@@ -144,17 +208,20 @@
 	struct playtones_state *ps = data;
 	struct playtones_item *pi;
 	int x;
-	/* we need to prepare a frame with 16 * timelen samples as we're 
-	 * generating SLIN audio
-	 */
+
+	/* we need to prepare a frame with 16 * timelen samples as we're
+	 * generating SLIN audio */
+
 	len = samples * 2;
 	if (len > sizeof(ps->data) / 2 - 1) {
 		ast_log(LOG_WARNING, "Can't generate that much data!\n");
 		return -1;
 	}
+
 	memset(&ps->f, 0, sizeof(ps->f));
 
 	pi = &ps->items[ps->npos];
+
 	if (ps->oldnpos != ps->npos) {
 		/* Load new parameters */
 		ps->v1_1 = 0;
@@ -165,80 +232,94 @@
 		ps->v3_2 = pi->init_v3_2;
 		ps->oldnpos = ps->npos;
 	}
+
 	for (x = 0; x < len/2; x++) {
 		ps->v1_1 = ps->v2_1;
 		ps->v2_1 = ps->v3_1;
 		ps->v3_1 = (pi->fac1 * ps->v2_1 >> 15) - ps->v1_1;
-		
+
 		ps->v1_2 = ps->v2_2;
 		ps->v2_2 = ps->v3_2;
 		ps->v3_2 = (pi->fac2 * ps->v2_2 >> 15) - ps->v1_2;
 		if (pi->modulate) {
 			int p;
 			p = ps->v3_2 - 32768;
-			if (p < 0) p = -p;
+			if (p < 0) {
+				p = -p;
+			}
 			p = ((p * 9) / 10) + 1;
 			ps->data[x] = (ps->v3_1 * p) >> 15;
-		} else
-			ps->data[x] = ps->v3_1 + ps->v3_2; 
-	}
-	
+		} else {
+			ps->data[x] = ps->v3_1 + ps->v3_2;
+		}
+	}
+
 	ps->f.frametype = AST_FRAME_VOICE;
 	ps->f.subclass = AST_FORMAT_SLINEAR;
 	ps->f.datalen = len;
 	ps->f.samples = samples;
 	ps->f.offset = AST_FRIENDLY_OFFSET;
 	ps->f.data.ptr = ps->data;
-	ps->f.delivery.tv_sec = 0;
-	ps->f.delivery.tv_usec = 0;
-	ast_write(chan, &ps->f);
+
+	if (ast_write(chan, &ps->f)) {
+		return -1;
+	}
 
 	ps->pos += x;
+
 	if (pi->duration && ps->pos >= pi->duration * 8) {	/* item finished? */
 		ps->pos = 0;					/* start new item */
 		ps->npos++;
 		if (ps->npos >= ps->nitems) {			/* last item? */
-			if (ps->reppos == -1)			/* repeat set? */
+			if (ps->reppos == -1) {			/* repeat set? */
 				return -1;
+			}
 			ps->npos = ps->reppos;			/* redo from top */
 		}
 	}
+
 	return 0;
 }
 
 static struct ast_generator playtones = {
-	alloc: playtones_alloc,
-	release: playtones_release,
-	generate: playtones_generator,
+	.alloc     = playtones_alloc,
+	.release   = playtones_release,
+	.generate  = playtones_generator,
 };
 
 int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst, int interruptible)
 {
-	char *s, *data = ast_strdupa(playlst); /* cute */
-	struct playtones_def d = { vol, -1, 0, 1, NULL};
+	char *s, *data = ast_strdupa(playlst);
+	struct playtones_def d = { vol, -1, 0, 1, NULL };
 	char *stringp;
 	char *separator;
-	
-	if (vol < 1)
+
+	if (vol < 1) {
 		d.vol = 7219; /* Default to -8db */
+	}
 
 	d.interruptible = interruptible;
-	
-	stringp=data;
-	/* the stringp/data is not null here */
+
+	stringp = data;
+
 	/* check if the data is separated with '|' or with ',' by default */
-	if (strchr(stringp,'|'))
+	if (strchr(stringp,'|')) {
 		separator = "|";
-	else
+	} else {
 		separator = ",";
-	s = strsep(&stringp,separator);
-	while (s && *s) {
+	}
+
+	while ((s = strsep(&stringp, separator)) && !ast_strlen_zero(s)) {
 		int freq1, freq2, duration, modulate = 0, midinote = 0;
 
-		if (s[0]=='!')
+		s = ast_strip(s);
+
+		if (s[0]=='!') {
 			s++;
-		else if (d.reppos == -1)
+		} else if (d.reppos == -1) {
 			d.reppos = d.nitems;
+		}
+
 		if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &duration) == 3) {
 			/* f1+f2/time format */
 		} else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
@@ -284,26 +365,34 @@
 			duration = 0;
 			midinote = 1;
 		} else {
-			ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n",chan->name,s,playlst);
+			ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n", chan->name, s, playlst);
 			return -1;
 		}
 
 		if (midinote) {
 			/* midi notes must be between 0 and 127 */
-			if ((freq1 >= 0) && (freq1 <= 127))
+
+			switch (freq1) {
+			case 0 ... 127:
 				freq1 = midi_tohz[freq1];
-			else
+				break;
+			default:
 				freq1 = 0;
-
-			if ((freq2 >= 0) && (freq2 <= 127))
+			}
+
+			switch (freq2) {
+			case 0 ... 127:
 				freq2 = midi_tohz[freq2];
-			else
+				break;
+			default:
 				freq2 = 0;
+			}
 		}
 
 		if (!(d.items = ast_realloc(d.items, (d.nitems + 1) * sizeof(*d.items)))) {
 			return -1;
 		}
+
 		d.items[d.nitems].fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
 		d.items[d.nitems].init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * d.vol;
 		d.items[d.nitems].init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * d.vol;
@@ -314,14 +403,13 @@
 		d.items[d.nitems].duration = duration;
 		d.items[d.nitems].modulate = modulate;
 		d.nitems++;
-
-		s = strsep(&stringp,separator);
 	}
 
 	if (ast_activate_generator(chan, &playtones, &d)) {
 		ast_free(d.items);
 		return -1;
 	}
+
 	return 0;
 }
 
@@ -332,263 +420,644 @@
 
 /*--------------------------------------------*/
 
-static AST_RWLIST_HEAD_STATIC(tone_zones, tone_zone);
-static struct tone_zone *current_tonezone;
-
-struct tone_zone *ast_walk_indications(const struct tone_zone *cur)
-{
-	struct tone_zone *tz = NULL;
-
-	AST_RWLIST_RDLOCK(&tone_zones);
-	/* If cur is not NULL, then we have to iterate through - otherwise just return the first entry */
-	if (cur) {
-		AST_RWLIST_TRAVERSE(&tone_zones, tz, list) {
-			if (tz == cur)
-				break;
-		}
-		tz = AST_RWLIST_NEXT(tz, list);
-	} else {
-		tz = AST_RWLIST_FIRST(&tone_zones);
-	}
-	AST_RWLIST_UNLOCK(&tone_zones);
-
-	return tz;
+struct ao2_iterator ast_tone_zone_iterator_init(void)
+{
+	return ao2_iterator_init(ast_tone_zones, 0);
 }
 
 /* Set global indication country */
-int ast_set_indication_country(const char *country)
-{
-	struct tone_zone *zone = NULL;
+static int ast_set_indication_country(const char *country)
+{
+	struct ast_tone_zone *zone = NULL;
 
 	/* If no country is specified or we are unable to find the zone, then return not found */
-	if (!country || !(zone = ast_get_indication_zone(country)))
+	if (ast_strlen_zero(country) || !(zone = ast_get_indication_zone(country))) {
 		return 1;
-	
+	}
+
 	ast_verb(3, "Setting default indication country to '%s'\n", country);
 
-	/* Protect the current tonezone using the tone_zones lock as well */
-	AST_RWLIST_WRLOCK(&tone_zones);
-	current_tonezone = zone;
-	AST_RWLIST_UNLOCK(&tone_zones);
-
-	/* Zone was found */
+	ao2_lock(ast_tone_zones);
+	if (default_tone_zone) {
+		default_tone_zone = ast_tone_zone_unref(default_tone_zone);
+	}
+	default_tone_zone = ast_tone_zone_ref(zone);
+	ao2_unlock(ast_tone_zones);
+
+	zone = ast_tone_zone_unref(zone);
+
 	return 0;
 }
 
-/* locate tone_zone, given the country. if country == NULL, use the default country */
-struct tone_zone *ast_get_indication_zone(const char *country)
-{
-	struct tone_zone *tz = NULL;
-	int alias_loop = 0;
-
-	AST_RWLIST_RDLOCK(&tone_zones);
+/* locate ast_tone_zone, given the country. if country == NULL, use the default country */
+struct ast_tone_zone *ast_get_indication_zone(const char *country)
+{
+	struct ast_tone_zone *tz = NULL;
+	struct ast_tone_zone zone_arg = {
+		.nrringcadence = 0,
+	};
 
 	if (ast_strlen_zero(country)) {
-		tz = current_tonezone ? current_tonezone : AST_LIST_FIRST(&tone_zones);
-	} else {
-		do {
-			AST_RWLIST_TRAVERSE(&tone_zones, tz, list) {
-				if (!strcasecmp(tz->country, country))
-					break;
-			}
-			if (!tz)
-				break;
-			/* If this is an alias then we have to search yet again otherwise we have found the zonezone */
-			if (tz->alias && tz->alias[0])
-				country = tz->alias;
-			else
-				break;
-		} while ((++alias_loop < 20) && tz);
-	}
-
-	AST_RWLIST_UNLOCK(&tone_zones);
-
-	/* If we reached the maximum loops to find the proper country via alias, print out a notice */
-	if (alias_loop == 20)
-		ast_log(LOG_NOTICE, "Alias loop for '%s' is bonkers\n", country);
-
-	return tz;
-}
-
-/* locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */
-struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication)
-{
-	struct tone_zone_sound *ts = NULL;
-
-	AST_RWLIST_RDLOCK(&tone_zones);
-
-	/* If no zone is already specified we need to try to pick one */
+		ao2_lock(ast_tone_zones);
+		if (default_tone_zone) {
+			tz = ast_tone_zone_ref(default_tone_zone);
+		}
+		ao2_unlock(ast_tone_zones);
+
+		return tz;
+	}
+
+	ast_copy_string(zone_arg.country, country, sizeof(zone_arg.country));
+
+	return ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER);
+}
+
+/* locate a ast_tone_zone_sound, given the ast_tone_zone. if ast_tone_zone == NULL, use the default ast_tone_zone */
+struct ast_tone_zone_sound *ast_get_indication_tone(const struct ast_tone_zone *_zone, const char *indication)
+{
+	struct ast_tone_zone_sound *ts = NULL;
+	/* _zone is const to the users of the API */
+	struct ast_tone_zone *zone = (struct ast_tone_zone *) _zone;
+
+	/* If no zone is specified, use the default */
 	if (!zone) {
-		if (current_tonezone) {
-			zone = current_tonezone;
-		} else if (!(zone = AST_LIST_FIRST(&tone_zones))) {
-			/* No zone has been found ;( */
-			AST_RWLIST_UNLOCK(&tone_zones);
+		ao2_lock(ast_tone_zones);
+		if (default_tone_zone) {
+			zone = ast_tone_zone_ref(default_tone_zone);
+		}
+		ao2_unlock(ast_tone_zones);
+
+		if (!zone) {
 			return NULL;
 		}
 	}
 
+	ast_tone_zone_lock(zone);
+
 	/* Look through list of tones in the zone searching for the right one */
-	AST_LIST_TRAVERSE(&zone->tones, ts, list) {
-		if (!strcasecmp(ts->name, indication))
+	AST_LIST_TRAVERSE(&zone->tones, ts, entry) {
+		/* XXX THE TONE ZONE SOUNDS NEED TO BE REF COUNTED TOO! */
+		if (!strcasecmp(ts->name, indication)) {
 			break;
-	}
-
-	AST_RWLIST_UNLOCK(&tone_zones);
+		}
+	}
+
+	ast_tone_zone_unlock(zone);
 
 	return ts;
 }
 
-static inline void clear_zone_sound(struct tone_zone_sound *ts)
+static void ast_tone_zone_sound_destroy(struct ast_tone_zone_sound *ts)
 {
 	/* Deconstify the 'const char *'s so the compiler doesn't complain. (but it's safe) */
-	ast_free((char *) ts->name);
-	ast_free((char *) ts->data);
+	if (ts->name) {
+		ast_free((char *) ts->name);
+		ts->name = NULL;
+	}
+
+	if (ts->data) {
+		ast_free((char *) ts->data);
+		ts->data = NULL;
+	}
+
+	ast_free(ts);
 }
 
 /*! \brief deallocate the passed tone zone */
-void ast_destroy_indication_zone(struct tone_zone *zone)
-{
-	struct tone_zone_sound *current;
-
-	while ((current = AST_LIST_REMOVE_HEAD(&zone->tones, list))) {
-		clear_zone_sound(current);
-		ast_free(current);
-	}
-
-	if (zone->ringcadence)
+static void ast_tone_zone_destructor(void *obj)
+{
+	struct ast_tone_zone *zone = obj;
+	struct ast_tone_zone_sound *current;
+
+	while ((current = AST_LIST_REMOVE_HEAD(&zone->tones, entry))) {
+		ast_tone_zone_sound_destroy(current);
+	}
+
+	if (zone->ringcadence) {
 		ast_free(zone->ringcadence);
-
-	ast_free(zone);
+		zone->ringcadence = NULL;
+	}
 }
 
 /*--------------------------------------------*/
 
 /* add a new country, if country exists, it will be replaced. */
-int ast_register_indication_country(struct tone_zone *zone)
-{
-	struct tone_zone *tz = NULL;
-
-	AST_RWLIST_WRLOCK(&tone_zones);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&tone_zones, tz, list) {
-		/* If this is not the same zone, then just continue to the next entry */
-		if (strcasecmp(zone->country, tz->country))
-			continue;
-		/* If this zone we are going to remove is the current default then make the new zone the default */
-		if (tz == current_tonezone)
-			current_tonezone = zone;
-		/* Remove from the linked list */
-		AST_RWLIST_REMOVE_CURRENT(list);
-		/* Finally free the zone itself */
-		ast_destroy_indication_zone(tz);
-		break;
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-
-	/* Add zone to the list */
-	AST_RWLIST_INSERT_TAIL(&tone_zones, zone, list);
-
-	/* It's all over. */
-	AST_RWLIST_UNLOCK(&tone_zones);
+static int ast_register_indication_country(struct ast_tone_zone *zone)
+{
+	ao2_lock(ast_tone_zones);
+	if (!default_tone_zone) {
+		default_tone_zone = ast_tone_zone_ref(zone);
+	}
+	ao2_unlock(ast_tone_zones);
+
+	ao2_link(ast_tone_zones, zone);
 
 	ast_verb(3, "Registered indication country '%s'\n", zone->country);
 
 	return 0;
 }
 
-/* remove an existing country and all its indications, country must exist.
- * Also, all countries which are an alias for the specified country are removed. */
-int ast_unregister_indication_country(const char *country)
-{
-	struct tone_zone *tz = NULL;
+/* remove an existing country and all its indications, country must exist. */
+static int ast_unregister_indication_country(const char *country)
+{
+	struct ast_tone_zone *tz = NULL;
+	struct ast_tone_zone zone_arg = {
+		.nrringcadence = 0,
+	};
+
+	ast_copy_string(zone_arg.country, country, sizeof(zone_arg.country));
+
+	if (!(tz = ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER))) {
+		return -1;
+	}
+
+	ao2_lock(ast_tone_zones);
+	if (default_tone_zone == tz) {
+		ast_tone_zone_unref(default_tone_zone);
+		/* Get a new default, punt to the first one we find */
+		default_tone_zone = ao2_callback(ast_tone_zones, 0, NULL, NULL);
+	}
+	ao2_unlock(ast_tone_zones);
+
+	ao2_unlink(ast_tone_zones, tz);
+
+	tz = ast_tone_zone_unref(tz);
+
+	return 0;
+}
+
+/* add a new indication to a ast_tone_zone. ast_tone_zone must exist. if the indication already
+ * exists, it will be replaced. */
+static int ast_register_indication(struct ast_tone_zone *zone, const char *indication, const char *tonelist)
+{
+	struct ast_tone_zone_sound *ts;
+
+	ast_tone_zone_lock(zone);
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, ts, entry) {
+		if (!strcasecmp(indication, ts->name)) {
+			AST_LIST_REMOVE_CURRENT(entry);
+			ast_tone_zone_sound_destroy(ts);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+
+	if (!(ts = ast_calloc(1, sizeof(*ts)))) {
+		ast_tone_zone_unlock(zone);
+		return -2;
+	}
+
+	if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) {
+		ast_tone_zone_unlock(zone);
+		ast_tone_zone_sound_destroy(ts);
+		return -2;
+	}
+
+	AST_LIST_INSERT_TAIL(&zone->tones, ts, entry);
+
+	ast_tone_zone_unlock(zone);
+
+	return 0;
+}
+
+/* remove an existing country's indication. Both country and indication must exist */
+static int ast_unregister_indication(struct ast_tone_zone *zone, const char *indication)
+{
+	struct ast_tone_zone_sound *ts;
 	int res = -1;
 
-	AST_RWLIST_WRLOCK(&tone_zones);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&tone_zones, tz, list) {
-		if (country && (strcasecmp(country, tz->country) && strcasecmp(country, tz->alias)))
-			continue;
-		/* If this tonezone is the current default then unset it */
-		if (tz == current_tonezone) {
-			ast_log(LOG_NOTICE,"Removed default indication country '%s'\n", tz->country);
-			current_tonezone = NULL;
-		}
-		/* Remove from the list */
-		AST_RWLIST_REMOVE_CURRENT(list);
-		ast_verb(3, "Unregistered indication country '%s'\n", tz->country);
-		ast_destroy_indication_zone(tz);
-		res = 0;
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-	AST_RWLIST_UNLOCK(&tone_zones);
-
-	return res;
-}
-
-/* add a new indication to a tone_zone. tone_zone must exist. if the indication already
- * exists, it will be replaced. */

[... 641 lines stripped ...]



More information about the asterisk-commits mailing list