/* Create the audio queue. */ int audio_queue_create(audio_queue_t **audio_queue, const char *name) { int status = 0; audio_queue_t *laudio_queue = NULL; char *lname = ""; apr_pool_t *pool; if (audio_queue == NULL) return -1; else *audio_queue = NULL; if ((pool = apt_pool_create()) == NULL) return -1; if ((name == NULL) || (strlen(name) == 0)) lname = ""; else lname = apr_pstrdup(pool, name); if (lname == NULL) lname = ""; if ((laudio_queue = (audio_queue_t *)apr_palloc(pool, sizeof(audio_queue_t))) == NULL) { ast_log(LOG_ERROR, "(%s) Unable to create audio queue\n", lname); return -1; } else { laudio_queue->buffer = NULL; laudio_queue->cond = NULL; laudio_queue->mutex = NULL; laudio_queue->name = lname; laudio_queue->pool = pool; laudio_queue->read_bytes = 0; laudio_queue->waiting = 0; laudio_queue->write_bytes = 0; if (audio_buffer_create(&laudio_queue->buffer, AUDIO_QUEUE_SIZE) != 0) { ast_log(LOG_ERROR, "(%s) Unable to create audio queue buffer\n", laudio_queue->name); status = -1; } else if (apr_thread_mutex_create(&laudio_queue->mutex, APR_THREAD_MUTEX_UNNESTED, pool) != APR_SUCCESS) { ast_log(LOG_ERROR, "(%s) Unable to create audio queue mutex\n", laudio_queue->name); status = -1; } else if (apr_thread_cond_create(&laudio_queue->cond, pool) != APR_SUCCESS) { ast_log(LOG_ERROR, "(%s) Unable to create audio queue condition variable\n", laudio_queue->name); status = -1; } else { *audio_queue = laudio_queue; ast_log(LOG_DEBUG, "(%s) Audio queue created\n", laudio_queue->name); } } if (status != 0) audio_queue_destroy(laudio_queue); return status; }
/* Destroy the speech channel. */ int speech_channel_destroy(speech_channel_t *schannel) { if (schannel == NULL) { ast_log(LOG_ERROR, "Speech channel structure pointer is NULL\n"); return -1; } ast_log(LOG_DEBUG, "Destroy speech channel: Name=%s, Type=%s, Codec=%s, Rate=%u\n", schannel->name, speech_channel_type_to_string(schannel->type), schannel->codec, schannel->rate); if (schannel->mutex) apr_thread_mutex_lock(schannel->mutex); #if SPEECH_CHANNEL_DUMP if(schannel->stream_out) { fclose(schannel->stream_out); schannel->stream_out = NULL; } if(schannel->stream_in) { fclose(schannel->stream_in); schannel->stream_in = NULL; } #endif /* Destroy the channel and session if not already done. */ if (schannel->state != SPEECH_CHANNEL_CLOSED) { int warned = 0; if ((schannel->unimrcp_session != NULL) && (schannel->unimrcp_channel != NULL)) { if (!mrcp_application_session_terminate(schannel->unimrcp_session)) ast_log(LOG_WARNING, "(%s) Unable to terminate application session\n", schannel->name); } ast_log(LOG_DEBUG, "(%s) Waiting for MRCP session to terminate\n", schannel->name); while (schannel->state != SPEECH_CHANNEL_CLOSED) { if (schannel->cond != NULL) { if ((apr_thread_cond_timedwait(schannel->cond, schannel->mutex, SPEECH_CHANNEL_TIMEOUT_USEC) == APR_TIMEUP) && (!warned)) { warned = 1; ast_log(LOG_WARNING, "(%s) MRCP session has not terminated after %d ms\n", schannel->name, SPEECH_CHANNEL_TIMEOUT_USEC / 1000); } } } } if (schannel->state != SPEECH_CHANNEL_CLOSED) { ast_log(LOG_ERROR, "(%s) Failed to destroy channel. Continuing\n", schannel->name); } if (schannel->dtmf_generator != NULL) { mpf_dtmf_generator_destroy(schannel->dtmf_generator); schannel->dtmf_generator = NULL; ast_log(LOG_DEBUG, "(%s) DTMF generator destroyed\n", schannel->name); } if (schannel->audio_queue != NULL) { if (audio_queue_destroy(schannel->audio_queue) != 0) ast_log(LOG_WARNING, "(%s) Unable to destroy channel audio queue\n",schannel->name); } if (schannel->mutex != NULL) apr_thread_mutex_unlock(schannel->mutex); if (schannel->cond != NULL) { if (apr_thread_cond_destroy(schannel->cond) != APR_SUCCESS) ast_log(LOG_WARNING, "(%s) Unable to destroy channel condition variable\n", schannel->name); } if (schannel->mutex != NULL) { if (apr_thread_mutex_destroy(schannel->mutex) != APR_SUCCESS) ast_log(LOG_WARNING, "(%s) Unable to destroy channel condition variable\n", schannel->name); } schannel->name = NULL; schannel->profile = NULL; schannel->application = NULL; schannel->unimrcp_session = NULL; schannel->unimrcp_channel = NULL; schannel->stream = NULL; schannel->dtmf_generator = NULL; schannel->pool = NULL; schannel->mutex = NULL; schannel->cond = NULL; schannel->audio_queue = NULL; schannel->codec = NULL; schannel->data = NULL; schannel->chan = NULL; return 0; }
speech_channel_t *speech_channel_create(apr_pool_t *pool, const char *name, speech_channel_type_t type, ast_mrcp_application_t *app, const char *codec, apr_uint16_t rate, struct ast_channel *chan) { speech_channel_t *schan = NULL; int status = 0; if (app == NULL) { ast_log(LOG_ERROR, "MRCP application is NULL\n"); status = -1; } else if (pool == NULL) { ast_log(LOG_ERROR, "Memory pool is NULL\n"); status = -1; } else if ((schan = (speech_channel_t *)apr_palloc(pool, sizeof(speech_channel_t))) == NULL) { ast_log(LOG_ERROR, "Unable to allocate speech channel structure\n"); status = -1; } else { if ((name == NULL) || (strlen(name) == 0)) { ast_log(LOG_WARNING, "No name specified, assuming \"TTS\"\n"); schan->name = "TTS"; } else schan->name = apr_pstrdup(pool, name); if ((schan->name == NULL) || (strlen(schan->name) == 0)) { ast_log(LOG_WARNING, "Unable to allocate name for channel, using \"TTS\"\n"); schan->name = "TTS"; } if ((codec == NULL) || (strlen(codec) == 0)) { ast_log(LOG_WARNING, "(%s) No codec specified, assuming \"L16\"\n", schan->name); schan->codec = "L16"; } else schan->codec = apr_pstrdup(pool, codec); if ((schan->codec == NULL) || (strlen(schan->codec) == 0)) { ast_log(LOG_WARNING, "(%s) Unable to allocate codec for channel, using \"L16\"\n", schan->name); schan->codec = "L16"; } schan->profile = NULL; schan->type = type; schan->application = app; schan->unimrcp_session = NULL; schan->unimrcp_channel = NULL; schan->stream = NULL; schan->dtmf_generator = NULL; schan->pool = pool; schan->mutex = NULL; schan->cond = NULL; schan->state = SPEECH_CHANNEL_CLOSED; schan->audio_queue = NULL; schan->rate = rate; schan->data = NULL; schan->chan = chan; if (strstr("L16", schan->codec)) { schan->silence = 0; } else { /* 8-bit PCMU, PCMA. */ schan->silence = 128; } if ((apr_thread_mutex_create(&schan->mutex, APR_THREAD_MUTEX_UNNESTED, pool) != APR_SUCCESS) || (schan->mutex == NULL)) { ast_log(LOG_ERROR, "(%s) Unable to create channel mutex\n", schan->name); status = -1; } else if ((apr_thread_cond_create(&schan->cond, pool) != APR_SUCCESS) || (schan->cond == NULL)) { ast_log(LOG_ERROR, "(%s) Unable to create channel condition variable\n",schan->name); status = -1; } else if ((audio_queue_create(&schan->audio_queue, name) != 0) || (schan->audio_queue == NULL)) { ast_log(LOG_ERROR, "(%s) Unable to create audio queue for channel\n",schan->name); status = -1; } else { ast_log(LOG_DEBUG, "Created speech channel: Name=%s, Type=%s, Codec=%s, Rate=%u\n", schan->name, speech_channel_type_to_string(schan->type), schan->codec, schan->rate); } } if (status != 0) { if (schan != NULL) { if (schan->audio_queue != NULL) { if (audio_queue_destroy(schan->audio_queue) != 0) ast_log(LOG_WARNING, "(%s) Unable to destroy channel audio queue\n", schan->name); } if (schan->cond != NULL) { if (apr_thread_cond_destroy(schan->cond) != APR_SUCCESS) ast_log(LOG_WARNING, "(%s) Unable to destroy channel condition variable\n", schan->name); schan->cond = NULL; } if (schan->mutex != NULL) { if (apr_thread_mutex_destroy(schan->mutex) != APR_SUCCESS) ast_log(LOG_WARNING, "(%s) Unable to destroy channel mutex variable\n", schan->name); } schan = NULL; } } #if SPEECH_CHANNEL_DUMP if(schan) { const char *stream_in_filename = apr_psprintf(pool,"%s/%s-%s-in.raw", SPEECH_CHANNEL_DUMP_DIR, schan->name, schan->codec); const char *stream_out_filename = apr_psprintf(pool,"%s/%s-%s-out.raw", SPEECH_CHANNEL_DUMP_DIR, schan->name, schan->codec); schan->stream_in = fopen(stream_in_filename,"wb"); if(!schan->stream_in) { ast_log(LOG_WARNING, "(%s) Unable to open input stream file for writing\n", schan->name); } schan->stream_out = fopen(stream_out_filename,"wb"); if(!schan->stream_out) { ast_log(LOG_WARNING, "(%s) Unable to open output stream file for writing\n", schan->name); } } #endif return schan; }