Merge some of Mahmut's patches
[asterisk/asterisk.git] / channels / chan_agent.c
index 61f5bb2..0b3d74e 100755 (executable)
@@ -223,21 +223,36 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
        struct agent_pvt *p = ast->pvt->pvt;
        int res = -1;
        ast_pthread_mutex_lock(&p->lock);
+       ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
+       ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
        res = ast_streamfile(p->chan, "beep", p->chan->language);
-       if (!res)
+       ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
+       if (!res) {
                res = ast_waitstream(p->chan, "");
+               ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
+       }
        if (!res) {
                res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
+               ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
                if (res)
                        ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(p->chan->nativeformats));
        }
+       else {
+               // Agent hung-up
+               p->chan = NULL;
+       }
+
        if (!res) {
                ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
+               ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
                if (res)
                        ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(p->chan->nativeformats));
        }
-       /* Call is immediately up */
-       ast_setstate(ast, AST_STATE_UP);
+       if( !res )
+       {
+               /* Call is immediately up */
+               ast_setstate(ast, AST_STATE_UP);
+       }
        CLEANUP(ast,p);
        ast_pthread_mutex_unlock(&p->lock);
        return res;
@@ -250,9 +265,6 @@ static int agent_hangup(struct ast_channel *ast)
        p->owner = NULL;
        ast->pvt->pvt = NULL;
        p->app_sleep_cond = 1;
-       ast_pthread_mutex_unlock(&p->lock);
-       /* Release ownership of the agent to other threads (presumably running the login app). */
-       ast_pthread_mutex_unlock(&p->app_lock);
        if (p->chan) {
                /* If they're dead, go ahead and hang up on the agent now */
                ast_pthread_mutex_lock(&p->chan->lock);
@@ -260,9 +272,20 @@ static int agent_hangup(struct ast_channel *ast)
                        ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
                ast_moh_start(p->chan, p->moh);
                ast_pthread_mutex_unlock(&p->chan->lock);
-       } else if (p->dead)
+               ast_pthread_mutex_unlock(&p->lock);
+               /* Release ownership of the agent to other threads (presumably running the login app). */
+               ast_pthread_mutex_unlock(&p->app_lock);
+       } else if (p->dead) {
                /* Go ahead and lose it */
+               ast_pthread_mutex_unlock(&p->lock);
+               /* Release ownership of the agent to other threads (presumably running the login app). */
+               ast_pthread_mutex_unlock(&p->app_lock);
                free(p);
+       } else {
+               ast_pthread_mutex_unlock(&p->lock);
+               /* Release ownership of the agent to other threads (presumably running the login app). */
+               ast_pthread_mutex_unlock(&p->app_lock);
+       }
 
        return 0;
 }
@@ -333,6 +356,15 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state)
                        ast_pthread_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
                        ast_pthread_mutex_lock(&p->app_lock);
                        ast_pthread_mutex_lock(&p->lock);
+                       if( !p->chan )
+                       {
+                               ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
+                               p->owner = NULL;
+                               tmp->pvt->pvt = NULL;
+                               p->app_sleep_cond = 1;
+                               ast_channel_free( tmp );
+                               return NULL;
+                       }
                }
                p->owning_app = pthread_self();
                /* After the above step, there should not be any blockers. */
@@ -486,9 +518,6 @@ static int login_exec(struct ast_channel *chan, void *data)
        char *opt_user = NULL;
        char *options = NULL;
        int play_announcement;
-       struct timespec required;
-       struct timespec remaining;
-       int delay;
        
        LOCAL_USER_ADD(u);
 
@@ -577,21 +606,12 @@ static int login_exec(struct ast_channel *chan, void *data)
                                                        ast_pthread_mutex_unlock(&p->lock);
                                                        ast_pthread_mutex_unlock(&agentlock);
                                                        while (res >= 0) {
-                                                               /* If we are not the owner, delay here for a while
-                                                                * so other interested threads can kick in. */
-                                                               delay = 0;
                                                                ast_pthread_mutex_lock(&p->lock);
                                                                if (p->chan != chan)
                                                                        res = -1;
-                                                               if (p->owner) 
-                                                                       delay = 1;
                                                                ast_pthread_mutex_unlock(&p->lock);
-                                                               if (delay) {
-                                                                       sched_yield();
-                                                                       required.tv_sec = 0;
-                                                                       required.tv_nsec = 20 * 1000 * 1000;
-                                                                       nanosleep( &required, &remaining );
-                                                               }
+                                                               /* Yield here so other interested threads can kick in. */
+                                                               sched_yield();
                                                                if (res)
                                                                        break;
 
@@ -603,12 +623,15 @@ static int login_exec(struct ast_channel *chan, void *data)
                                                                res = ast_safe_sleep_conditional( chan, 1000,
                                                                                                                agent_cont_sleep, p );
                                                                pthread_mutex_unlock( &p->app_lock );
+                                                               sched_yield();
                                                        }
+                                                       ast_pthread_mutex_lock(&p->lock);
                                                        if (res && p->owner) 
                                                                ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
                                                        /* Log us off if appropriate */
                                                        if (p->chan == chan)
                                                                p->chan = NULL;
+                                                       ast_pthread_mutex_unlock(&p->lock);
                                                        if (option_verbose > 2)
                                                                ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
                                                        manager_event(EVENT_FLAG_AGENT, "Agentlogoff",