[asterisk-commits] russell: branch russell/chan_console r49017 - /team/russell/chan_console/chan...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu Dec 28 05:43:36 MST 2006


Author: russell
Date: Thu Dec 28 06:43:35 2006
New Revision: 49017

URL: http://svn.digium.com/view/asterisk?view=rev&rev=49017
Log:
- Place common code for starting and stopping the audio stream in functions
- Hackishly work around a couple of different deadlocks.

Modified:
    team/russell/chan_console/channels/chan_console.c

Modified: team/russell/chan_console/channels/chan_console.c
URL: http://svn.digium.com/view/asterisk/team/russell/chan_console/channels/chan_console.c?view=diff&rev=49017&r1=49016&r2=49017
==============================================================================
--- team/russell/chan_console/channels/chan_console.c (original)
+++ team/russell/chan_console/channels/chan_console.c Thu Dec 28 06:43:35 2006
@@ -65,12 +65,16 @@
 	ast_cond_t cond;
 	unsigned int hookstate:1;
 	unsigned int overridecontext:1;
+	unsigned int incallback:1;
 	AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
 } pvt = {
 	.name = "default",
 };
 
 AST_MUTEX_DEFINE_STATIC(console_lock);
+
+static int start_stream(void);
+static int stop_stream(void);
 
 static struct ast_channel *console_request(const char *type, int format, 
 	void *data, int *cause);
@@ -183,49 +187,37 @@
 
 static int console_hangup(struct ast_channel *c)
 {
-	PaError err;
 	int res = 0;
 
 	ast_verbose(" -=- Hangup on Console -=-\n");
+
+	while (pvt.incallback) /* :( */
+		usleep(10);
 
 	ast_mutex_lock(&console_lock);
 	c->tech_pvt = NULL;
 	pvt.owner = NULL;
-	if (pvt.hookstate) {
-		err = Pa_StopStream(pvt.stream);
-		if (err != paNoError) {
-			ast_log(LOG_WARNING, "Error stopping stream!\n");
-			res = -1;
-		}
-		pvt.hookstate = 0;
-	}
+	if (pvt.hookstate)
+		stop_stream();
+	ast_mutex_unlock(&console_lock);
+
+	return res;
+}
+
+static int console_answer(struct ast_channel *c)
+{
+	int res = 0;
+
+	ast_verbose(" -=- Call from Console has been Answered -=-\n");
+
 	ast_mutex_lock(&console_lock);
+	ast_setstate(c, AST_STATE_UP);
+	res = start_stream();
+	ast_mutex_unlock(&console_lock);
 
 	return res;
 }
 
-static int console_answer(struct ast_channel *c)
-{
-	PaError err;
-	int res = 0;
-
-	ast_verbose(" -=- Call from Console has been Answered -=-\n");
-
-	ast_mutex_lock(&console_lock);
-
-	ast_setstate(c, AST_STATE_UP);
-
-	err = Pa_StartStream(pvt.stream);
-	if (err != paNoError) {
-		ast_log(LOG_WARNING, "Error starting stream!\n");
-		res = -1;
-	}
-
-	ast_mutex_unlock(&console_lock);
-
-	return 0;
-}
-
 static struct ast_frame *console_read(struct ast_channel *chan)
 {
 	ast_log(LOG_WARNING, "This should never be called, mmkay?!\n");
@@ -236,7 +228,6 @@
 static int console_call(struct ast_channel *c, char *dest, int timeout)
 {
 	struct ast_frame f = { 0, };
-	PaError err;
 	int res = 0;
 
 	ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console "
@@ -248,11 +239,7 @@
 	f.subclass = AST_CONTROL_ANSWER;
 	ast_queue_frame(c, &f);
 
-	err = Pa_StartStream(pvt.stream);
-	if (err != paNoError) {
-		ast_log(LOG_WARNING, "Error starting stream!\n");
-		res = -1;
-	}
+	res = start_stream();
 
 	return res;
 }
@@ -260,8 +247,6 @@
 static int console_write(struct ast_channel *chan, struct ast_frame *f)
 {
 	struct ast_frame *fr = ast_frdup(f);
-
-	//ast_log(LOG_NOTICE, "console_write...\n");
 
 	if (!fr)
 		return -1; 
@@ -291,7 +276,7 @@
 	unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info,
 	PaStreamCallbackFlags flags, void *userData)
 {
-	//ast_log(LOG_NOTICE, "console_callback, frame_count: %lu ...\n", frame_count);
+	pvt.incallback = 1;
 
 	if (output) {
 		unsigned int src = 0;
@@ -300,24 +285,28 @@
 		ast_mutex_lock(&console_lock);
 		if (pvt.write_dst) {
 			num_samples = (pvt.write_dst * 2) > frame_count ? pvt.write_dst * 2 : frame_count;
-			//ast_log(LOG_NOTICE, "writing %d samples from write_buf\n", num_samples);
 			memcpy(output, &pvt.write_buf, num_samples * 2);
 			pvt.write_dst -= num_samples * 2;
 			src += num_samples * 2;
 			frame_count -= num_samples;
 		}
 		while (frame_count) { 
-			while (!(fr = AST_LIST_REMOVE_HEAD(&pvt.frames, frame_list)))
+			while (!(fr = AST_LIST_REMOVE_HEAD(&pvt.frames, frame_list))) {
 				ast_cond_wait(&pvt.cond, &console_lock);
+				if (!pvt.hookstate) {
+					if (fr)
+						ast_frfree(fr);
+					ast_mutex_unlock(&console_lock);
+					pvt.incallback = 0;
+					return paAbort;	
+				}
+			}
 			num_samples = fr->samples > frame_count ? frame_count : fr->samples;
-			//ast_log(LOG_NOTICE, "Writing %d samples from frame\n", num_samples);
 			memcpy(output + src, fr->data, num_samples * 2);
 			frame_count -= num_samples;
 			if (num_samples != fr->samples) {
 				memcpy(&pvt.write_buf + pvt.write_dst, fr->data + num_samples * 2, (fr->samples - num_samples) * 2);
 				pvt.write_dst += (fr->samples - num_samples) * 2;
-				//ast_log(LOG_NOTICE, "Saving %d bytes (%d samples) left over in frame\n", 
-					//(fr->samples - num_samples) * 2, (fr->samples - num_samples) * 2);
 			}
 			ast_frfree(fr);
 		}
@@ -331,6 +320,7 @@
 
 	if (input) {
 		struct ast_frame *fr = &pvt.fr;
+		unsigned int count = 0;
 		memset(fr, 0, sizeof(*fr));
 		memset(pvt.read_buf, 0, NUM_SAMPLES * 2 + AST_FRIENDLY_OFFSET);
 		fr->data = pvt.read_buf + AST_FRIENDLY_OFFSET;
@@ -340,9 +330,19 @@
 		fr->samples = NUM_SAMPLES;
 		fr->datalen = NUM_SAMPLES * 2;
 		memcpy(fr->data, input, NUM_SAMPLES * 2);
+		while (ast_channel_trylock(pvt.owner)) {
+			if (++count == 100) {
+				ast_log(LOG_DEBUG, "Dropping frame\n");
+				pvt.incallback = 0;
+				return paContinue;	
+			}
+			usleep(10);
+		}
 		ast_queue_frame(pvt.owner, fr);
-	}
-
+		ast_channel_unlock(pvt.owner);
+	}
+
+	pvt.incallback = 0;
 	return paContinue;
 }
 
@@ -413,8 +413,7 @@
 	if (a->argc == e->args + 1) {
 		s = ast_ext_ctx(a->argv[e->args], &mye, &myc);
 		ast_log(LOG_NOTICE, "provided '%s', exten '%s' context '%s'\n", a->argv[e->args], mye, myc);
-	} else
-		ast_log(LOG_NOTICE, "No exten?\n");
+	}
 	/* supply default values if needed */
 	if (mye == NULL)
 		mye = "s";
@@ -459,21 +458,53 @@
 	NEW_CLI(cli_console_hangup, "Hangup a call on the console"),
 };
 
+static int start_stream(void)
+{
+	PaError res;
+
+	res = Pa_OpenDefaultStream(&pvt.stream, INPUT_CHANNELS, OUTPUT_CHANNELS, 
+		paInt16, SAMPLE_RATE, NUM_SAMPLES, console_callback, NULL);
+	if (res != paNoError) {
+		ast_log(LOG_WARNING, "Failed to open default audio device - (%d) %s\n",
+			res, Pa_GetErrorText(res));
+		return -1;
+	}
+
+	res = Pa_StartStream(pvt.stream);
+	if (res != paNoError) {
+		ast_log(LOG_WARNING, "Failed to start stream - (%d) %s\n",
+			res, Pa_GetErrorText(res));
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \note Called with console_lock locked
+ */
+static int stop_stream(void)
+{
+	if (pvt.hookstate) {
+		Pa_AbortStream(pvt.stream);
+		Pa_CloseStream(pvt.stream);
+		pvt.hookstate = 0;
+		ast_cond_signal(&pvt.cond);
+	}
+
+	return 0;
+}
+
 static int unload_module(void)
 {
-	PaError res;
+	ast_mutex_lock(&console_lock);
+	stop_stream();
+	ast_mutex_unlock(&console_lock);
+	Pa_Terminate();
 
 	ast_channel_unregister(&console_tech);
 	ast_cli_unregister_multiple(cli_console, sizeof(cli_console) / sizeof(cli_console[0]));
 
-	res = Pa_CloseStream(pvt.stream);
-	if (res != paNoError) {
-		ast_log(LOG_WARNING, "Failed to close default audio device - (%d) %s\n",
-			res, Pa_GetErrorText(res));
-		return -1;
-	}
-	Pa_Terminate();
-
 	ast_cond_destroy(&pvt.cond);
 
 	return 0;
@@ -482,6 +513,8 @@
 static int load_module(void)
 {
 	PaError res;
+
+	ast_cond_init(&pvt.cond, NULL);
 
 	res = Pa_Initialize();
 	if (res != paNoError) {
@@ -490,20 +523,8 @@
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	res = Pa_OpenDefaultStream(&pvt.stream, INPUT_CHANNELS, OUTPUT_CHANNELS, 
-		paInt16, SAMPLE_RATE, NUM_SAMPLES, console_callback, NULL);
-	if (res != paNoError) {
-		ast_log(LOG_WARNING, "Failed to open default audio device - (%d) %s\n",
-			res, Pa_GetErrorText(res));
-		return AST_MODULE_LOAD_DECLINE;
-	}
-
-	ast_cond_init(&pvt.cond, NULL);
-
 	if (ast_channel_register(&console_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel type 'Console'\n");
-		Pa_CloseStream(pvt.stream);
-		Pa_Terminate();
 		ast_cond_destroy(&pvt.cond);
 		return AST_MODULE_LOAD_DECLINE;
 	}



More information about the asterisk-commits mailing list