chan-capi/divastreaming/diva_streaming_manager.c

371 lines
13 KiB
C

/*
*
Copyright (c) Dialogic (R) 2009 - 2010
*
This source file is supplied for the use with
Eicon Networks range of DIVA Server Adapters.
*
Dialogic (R) File Revision : 1.9
*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
*
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU 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.
*
*/
#include "platform.h"
#include "pc.h"
#include "diva_streaming_result.h"
#include "diva_streaming_vector.h"
#include "diva_streaming_manager.h"
#include "diva_streaming_messages.h"
#include "diva_segment_alloc_ifc.h"
#include "diva_streaming_idi_host_ifc.h"
typedef struct _diva_stream_manager {
diva_stream_t ifc;
int user_segment_alloc;
struct _diva_segment_alloc* segment_alloc;
diva_segment_alloc_access_t* segment_alloc_ifc;
struct _diva_streaming_idi_host_ifc_w* tx;
struct _diva_streaming_idi_host_ifc_w_access* tx_ifc;
struct _diva_streaming_idi_host_ifc_r* rx;
struct _diva_streaming_idi_host_ifc_r_access* rx_ifc;
diva_streaming_idi_rx_notify_user_proc_t rx_proc;
void* rx_proc_context;
byte description[0xff-32];
char trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH+1];
} diva_stream_manager_t;
/*
* LOCALS
*/
static int message_input_proc (void* user_context, dword message, dword length, const diva_streaming_vector_t* v, dword nr_v);
static diva_streaming_idi_result_t diva_stream_manager_release (struct _diva_stream* ifc);
static diva_streaming_idi_result_t diva_stream_manager_release_stream (struct _diva_stream* ifc);
static diva_streaming_idi_result_t diva_stream_manager_write (struct _diva_stream* ifc, dword message, const void* data, dword length);
static diva_streaming_idi_result_t diva_stream_manager_wakeup (struct _diva_stream* ifc);
static const byte* diva_stream_manager_description (struct _diva_stream* ifc, const byte* addie, byte addielen);
static diva_streaming_idi_result_t diva_stream_manager_sync_req (struct _diva_stream* ifc, dword ident);
static diva_streaming_idi_result_t diva_stream_flush (struct _diva_stream* ifc);
static dword diva_stream_get_tx_free (const struct _diva_stream* ifc);
static dword diva_stream_get_tx_in_use (const struct _diva_stream* ifc);
static void diva_notify_os_resource_removed (struct _diva_stream* ifc);
diva_streaming_idi_result_t diva_stream_create (struct _diva_stream** ifc,
void* os_context,
dword length,
diva_streaming_idi_rx_notify_user_proc_t rx,
void* rx_context,
const char* trace_ident) {
return (diva_stream_create_with_user_segment_alloc (ifc, os_context, length, rx, rx_context, trace_ident, 0));
}
diva_streaming_idi_result_t diva_stream_create_with_user_segment_alloc (struct _diva_stream** ifc,
void* os_context,
dword length,
diva_streaming_idi_rx_notify_user_proc_t rx,
void* rx_context,
const char* trace_ident,
struct _diva_segment_alloc* user_segment_alloc) {
diva_stream_manager_t* pI;
diva_streaming_idi_result_t ret = DivaStreamingIdiResultError;
#ifdef DIVA_USERMODE
dbg_init ("DIVA STREAM", "109-1", 0);
#endif
pI = diva_os_malloc (0, sizeof(*pI));
if (pI != 0) {
memset (pI, 0x00, sizeof(*pI));
memcpy(pI->trace_ident, trace_ident, MIN(strlen(trace_ident), DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH));
pI->trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH] = 0;
if (user_segment_alloc != 0) {
pI->segment_alloc = user_segment_alloc;
pI->user_segment_alloc = 1;
ret = 0;
} else {
ret = diva_create_segment_alloc (os_context, &pI->segment_alloc);
pI->user_segment_alloc = 0;
}
if (ret == 0) {
dword number_segments = length/4096 + ((length%4096) != 0);
pI->segment_alloc_ifc = diva_get_segment_alloc_ifc (pI->segment_alloc);
ret = diva_streaming_idi_host_ifc_create (&pI->tx, number_segments, pI->segment_alloc, trace_ident);
if (ret == 0) {
pI->tx_ifc = diva_streaming_idi_host_ifc_get_access (pI->tx);
ret = diva_streaming_idi_host_rx_ifc_create (&pI->rx, number_segments, pI->segment_alloc, pI->tx, pI->tx_ifc, message_input_proc, pI, &pI->ifc, trace_ident);
if (ret == 0) {
pI->rx_ifc = diva_streaming_idi_host_rx_ifc_get_access (pI->rx);
pI->ifc.release = diva_stream_manager_release;
pI->ifc.release_stream = diva_stream_manager_release_stream;
pI->ifc.write = diva_stream_manager_write;
pI->ifc.wakeup = diva_stream_manager_wakeup;
pI->ifc.description = diva_stream_manager_description;
pI->ifc.sync = diva_stream_manager_sync_req;
pI->ifc.flush_stream = diva_stream_flush;
pI->ifc.get_tx_free = diva_stream_get_tx_free;
pI->ifc.get_tx_in_use = diva_stream_get_tx_in_use;
pI->ifc.notify_os_resource_removed = diva_notify_os_resource_removed;
pI->rx_proc = rx;
pI->rx_proc_context = rx_context;
*ifc = &pI->ifc;
ret = DivaStreamingIdiResultOK;
} else {
DBG_ERR(("failed to create rx stream [%s]", trace_ident))
}
} else {
DBG_ERR(("failed to create tx stream [%s]", trace_ident))
}
} else {
DBG_ERR(("failed to create segment alloc [%s]", trace_ident))
}
}
if (ret != 0)
diva_stream_manager_release (&pI->ifc);
return (ret);
}
static int message_input_proc (void* user_context, dword message, dword length, const diva_streaming_vector_t* v, dword nr_v) {
diva_stream_manager_t* pI = (diva_stream_manager_t*)user_context;
return (pI->rx_proc (pI->rx_proc_context, message, length, v, nr_v));
}
static diva_streaming_idi_result_t diva_stream_manager_release (struct _diva_stream* ifc) {
if (ifc != 0) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
if (pI->rx != 0)
pI->rx_ifc->release (pI->rx);
if (pI->tx != 0)
pI->tx_ifc->release (pI->tx);
if (pI->segment_alloc != 0 && pI->user_segment_alloc == 0)
pI->segment_alloc_ifc->release (&pI->segment_alloc);
diva_os_free (0, pI);
}
return (DivaStreamingIdiResultOK);
}
static diva_streaming_idi_result_t diva_stream_manager_release_stream (struct _diva_stream* ifc) {
if (ifc != 0) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
return (pI->tx_ifc->release_stream (pI->tx));
}
return (DivaStreamingIdiResultError);
}
static diva_streaming_idi_result_t diva_stream_manager_write (struct _diva_stream* ifc, dword message, const void* data, dword length) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
return (pI->tx_ifc->write_message (pI->tx, message, data, length));
}
static diva_streaming_idi_result_t diva_stream_manager_wakeup (struct _diva_stream* ifc) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
return (pI->rx_ifc->wakeup (pI->rx));
}
const byte* diva_stream_manager_description (struct _diva_stream* ifc, const byte* addie, byte addielen) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
byte length = 4, len_tx, len_rx;
len_tx = pI->tx_ifc->description (pI->tx, &pI->description[length], sizeof(pI->description)-length);
if (len_tx != 0) {
length += len_tx;
len_rx = pI->rx_ifc->description (pI->rx, &pI->description[length], sizeof(pI->description)-length);
if (len_rx != 0) {
length += len_rx;
pI->description[0] = length-1; /* Structure length */
pI->description[1] = 0; /* Request */
pI->description[2] = len_rx+len_tx+1; /* Structure length */
pI->description[3] = 0; /* Version */
if (addie != 0 && addielen != 0) {
byte* description = &pI->description[0];
byte* start = &description[3];
start[0] |= 2U;
start = start + start[-1];
memcpy (start, addie, addielen);
start += addielen;
*start++ = 0;
description[2] += addielen+1;
description[0] += addielen+1;
length += addielen+1;
}
DBG_TRC(("description length %u [%s]", length, pI->trace_ident))
DBG_BLK(((void*)pI->description, length))
return (&pI->description[0]);
}
}
return (0);
}
static diva_streaming_idi_result_t diva_stream_manager_sync_req (struct _diva_stream* ifc, dword ident) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
return (pI->tx_ifc->sync (pI->tx, ident));
}
static diva_streaming_idi_result_t diva_stream_flush (struct _diva_stream* ifc) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
return (pI->tx_ifc->update_remote (pI->tx) == 0 ? DivaStreamingIdiResultOK : DivaStreamingIdiResultError);
}
static dword diva_stream_get_tx_free (const struct _diva_stream* ifc) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
return (pI->tx_ifc->get_free (pI->tx));
}
static dword diva_stream_get_tx_in_use (const struct _diva_stream* ifc) {
const diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, const diva_stream_manager_t, ifc);
return (pI->tx_ifc->get_in_use (pI->tx));
}
static void diva_notify_os_resource_removed (struct _diva_stream* ifc) {
diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc);
if (pI->segment_alloc != 0) {
pI->segment_alloc_ifc->resource_removed (pI->segment_alloc);
}
}
dword diva_streaming_read_vector_data (const diva_streaming_vector_t* v, int nr_v, dword *vector_offset, dword *vector_position, byte* dst, dword length) {
dword to_copy;
dword count;
for (count = 0; vector_offset[0] < ((dword)nr_v) && length != 0;) {
to_copy = MIN((v[vector_offset[0]].length - vector_position[0]), length);
if (dst != 0) {
const byte* tmp = v[vector_offset[0]].data;
memcpy (dst, &tmp[vector_position[0]], to_copy);
dst += to_copy;
}
length -= to_copy;
count += to_copy;
if (v[vector_offset[0]].length == vector_position[0]+to_copy) {
vector_offset[0]++;
vector_position[0]=0;
} else {
vector_position[0] += to_copy;
}
}
return (count);
}
dword diva_streaming_get_indication_data (dword handle, dword message, dword length, const diva_streaming_vector_t* v, int nr_v, byte* pInd, diva_streaming_vector_t* vind, int *pvind_nr) {
dword vector_offset = (byte)handle;
dword vector_position = handle >> 8;
byte Ind = (byte)(message >> 8);
byte header[4];
dword indication_data_length;
int dst_nr_v = *pvind_nr;
int i;
if ((Ind & 0x0f) == 8 /* N_DATA */) {
*pInd = Ind;
for (i = 0; i < nr_v; i++) {
vind[i] = v[i];
}
*pvind_nr = nr_v;
return (0);
}
/*
Combined indication
data[0] = Ind;
data[1] = IndCh;
data[2] = (byte)length;
data[3] = (byte)(length >> 8);
*/
if (vector_offset >= ((dword)nr_v) || vector_position >= v[vector_offset].length) {
DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__))
*pInd = 0;
return (0);
}
{
const byte* tmp = v[vector_offset].data;
if (tmp[vector_position] == 0) {
DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__))
*pInd = 0;
return (0);
}
}
if (diva_streaming_read_vector_data (v, nr_v, &vector_offset, &vector_position, header, sizeof(header)) != sizeof(header)) {
DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__))
*pInd = 0;
return (0);
}
indication_data_length = ((word)header[2] | (word)header[3] << 8);
for (i = 0; i < dst_nr_v && indication_data_length != 0; i++) {
const byte* tmp = v[vector_offset].data;
vind[i].data = &tmp[vector_position];
vind[i].length = MIN((v[vector_offset].length - vector_position), indication_data_length);
*pvind_nr = i + 1;
indication_data_length -= vind[i].length;
if (diva_streaming_read_vector_data (v, nr_v, &vector_offset, &vector_position, 0, vind[i].length) != vind[i].length) {
DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__))
*pInd = 0;
return (0);
}
}
if (indication_data_length != 0) {
DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__))
*pInd = 0;
return (0);
}
*pInd = header[0];
{
const byte* tmp = v[vector_offset].data;
if (tmp[vector_position] == 0) {
return (0);
}
}
return (vector_offset | (vector_position << 8));
}