Отчет по практике


Разработка функций для класса интерфейса между модулем УШ и модулем протокола RTP

Введение


IP-телефония

IP-телефония - технология, позволяющая использовать сеть с пакетной коммутацией на базе протокола IP в качестве средств организации и ведения междугородных, международных и местных телефонных разговоров и передачи факсов в режиме реального времени.

Уровни архитектуры IP-телефонии

Архитектура технологии Voice over IP может быть упрощенно представлена в виде двух плоскостей. Нижняя плоскость - это базовая сеть с маршрутизацией пакетов IP, верхняя плоскость - это открытая архитектура управления обслуживанием вызовов (запросов связи).

Нижняя плоскость, представляет собой комбинацию известных протоколов Интернет: это - RTP (Real Time Transport Protocol), который функционирует поверх протокола UDP (User Datagram Protocol), расположенного, в свою очередь, в стеке протоколов TCP/IP над протоколом IP. Таким образом, иерархия RTP/UDP/IP представляет собой своего рода транспортный механизм для речевого трафика. Отметим, что в сетях с маршрутизацией пакетов IP для передачи данных всегда предусматриваются механизмы повторной передачи пакетов в случае их потери. При передаче информации в реальном времени использование таких механизмов только ухудшит ситуацию, поэтому для передачи информации, чувствительной к задержкам, но менее чувствительной к потерям, такой как речь и видеоинформация, используется механизм негарантированной доставки информации RTP/UDP/IP.

Управление обслуживанием вызова предусматривает принятие решений о том, куда вызов должен быть направлен, и каким образом должно быть установлено соединение между абонентами.

Особенности передачи речевой информации по IP - сетям


Проблемы ограничения задержки и подавления эха в традиционной телефонии существовали всегда, при переходе к IP-сетям они ухудшились. Добавились новые проблемы потери пакетов, случайного изменения времени задержки пакетов, а также нарушения порядка прибытия пакетов. Задержки представляют собой проблему и сами по себе, но, кроме того, усложнят проблему эха.

Задержка (или время запаздывания) определяется как промежуток времени, затрачиваемый на то, чтобы речевой сигнал прошел расстояние от говорящего до слушающего.

Время задержки при передаче речевого сигнала можно отнести к одному из трех уровней:

1.первый уровень до 200 мс - отличное качество связи. Для сравнения, в телефонной сети общего пользования допустимы задержки до 150-200 мс;


2.второй уровень до 400 мс - считается хорошим качеством связи. Но если сравнивать с качеством связи по сетям ТФОП, то разница будет видна. Если задержки постоянно удерживается на верхней границе 2-го уровня (на 400 мс), то не рекомендуется использовать эту связь для деловых переговоров;


.третий уровень до 700 мс - считается приемлемым качеством связи для ведения неделовых переговоров. Такое качество связи возможно также при передаче пакетов по спутниковой связи.


Общая задержка речевой информации делится на две основные части - задержка, вносимая самой сетью, и задержка между сетевым интерфейсом и устройством вывода речи (телефоном).

Сеть


Если нагрузка сети относительно мала, маршрутизаторы и коммутаторы, могут обрабатывать пакеты практически мгновенно, а линии связи доступны почти всегда. Если загрузка сети относительно велика, пакеты могут довольно долго ожидать обслуживания в очередях. Чем больше маршрутизаторов, коммутаторов и линий в маршруте, по которому проходит пакет, тем больше время его запаздывания, и тем больше вариация этого времени, т.е. джиттер.


Оконечное оборудование


Процесс передачи речи состоит из нескольких этапов.

На первом этапе осуществляется оцифровка речи. Затем оцифрованные данные анализируются и обрабатываются кодеками с целью уменьшения физического объема данных, передаваемых получателю. Как правило, на этом этапе происходит подавление пауз, фильтрация фонового шума, а также сжатие данных.

На следующем этапе происходит формирование RTP пакетов. При этом на стороне отправителя в буфере отправления происходит временное накопление необходимого количества данных для образования до его непосредственной передачи по сети. Затем пакеты отправляются в сокет.

Извлечение переданной речевой информации из полученных из сокета RTP-пакетов также происходит поэтапно, где проверяется очередность их доставки. Вследствие того, что в IP-сетях отсутствует гарантия времени доставки пакетов, RTP-пакеты со старшими порядковыми номерами могут прийти раньше. Некоторые пакеты могут быть вообще потеряны при доставке, или величина задержки при их передаче превышает нормативное значение времени ожидания. Для речевого трафика задержка и вариация задержки пакета являются критичными показателями, поэтому в таком случае либо используется алгоритм аппроксимации, позволяющий на основе полученных IP пакетов приблизительно восстановить потерянные, либо эти потери игнорируются. Полученная таким образом последовательность данных передается для обработки кодеками и преобразуется непосредственно в речевой сигнал.

Выполнение этой работы также сказывается на задержке.


Влияние операционной системы


Большинство приложений IP-телефонии представляет собой обычные программы, выполняемые в среде какой-либо операционной системы, такой как Windows или Linux. Эти программы обращаются к периферийным устройствам (платам обработки речевых сигналов, специализированным платам систем сигнализации) через интерфейс прикладных программ для взаимодействия с драйверами этих устройств, а доступ к IP-сети осуществляют через Socket-интерфейс.

Большинство операционных систем не может контролировать распределение времени центрального процессора между разными процессами с точностью, превышающей несколько десятков миллисекунд, и не может обрабатывать за такое же время более одного прерывания от внешних устройств. Это приводит к тому, что задержка в продвижении данных между сетевым интерфейсом и внешним устройством речевого вывода составляет, независимо от используемого алгоритма кодирования речи, величину такого же порядка, или даже больше.

Чтобы минимизировать влияние операционной системы, некоторые производители шлюзов и IP-телефонов используют ОС реального времени (VxWorks, pSOS, QNX Neutrino и т.д.), которые используют более сложные механизмы разделения времени процессора, действующие таким образом, чтобы обеспечивать значительно более быструю реакцию на прерывания и более эффективный обмен потоками данных между процессами.

Другой, более плодотворный подход - переложить все функции, которые необходимо выполнять в жестких временных рамках (обмен данными между речевыми кодеками и сетевым интерфейсом, поддержку RTP и т.д.), на отдельный быстродействующий специализированный процессор. При этом пересылка речевых данных осуществляется через выделенный сетевой интерфейс периферийного устройства, а операционная система рабочей станции поддерживает только алгоритмы управления соединениями и протоколы сигнализации, т.е. задачи, для выполнения которых жестких временных рамок не требуется. Этот подход реализован в платах для приложений IP-телефонии, производимых фирмами Dialogic, Audiocodes, Natural Microsystems. По такой же технологии выполнен и шлюз IP-телефонии в платформе Протей, что позволило обеспечить высокое качество передачи речи.


Джиттер-буфер


Отправитель речевых пакетов передает их через фиксированные промежутки времени (например, через каждые 20 мс), но при прохождении через сеть задержки пакетов оказываются неодинаковыми, так что они прибывают в пункт назначения через разные промежутки времени.

Для того чтобы компенсировать влияние джиттера, в терминалах используется джиттер-буфер. Этот буфер хранит в памяти прибывшие пакеты в течение времени, определяемого его емкостью (длиной). Интервалы между пакетами восстанавливаются на основе значений временных меток RTP-пакетов.


Кодек и количество передаваемых в пакете кадров


Большинство современных эффективных алгоритмов кодирования/декодирования речи ориентировано на передачу информации кадрами, а не последовательностью кодов отдельных отсчетов. Поэтому в течение времени, определяемого длиной кадра кодека, должна накапливаться определенной длины последовательность цифровых представлений отсчетов. Кроме того, некоторым кодекам необходим предварительный анализ большего количества речевой информации, чем должно содержаться в кадре. Это неизбежное время накопления и предварительного анализа входит в общий бюджет длительности задержки пакета.

На первый взгляд, можно было бы заключить, что чем меньше длина кадра, тем меньше должна быть задержка. Однако из-за значительного объема служебной информации, передаваемой в RTP/UDP/IP-пакетах, передача маленьких порций данных очень неэффективна, так что при применении кодеков с малой длиной кадра приходится упаковывать несколько кадров в один пакет. Кроме того, кодеки с большей длиной кадра более эффективны, поскольку могут «наблюдать» сигнал в течение большего времени и, следовательно, могут более эффективно моделировать этот сигнал.


Взаимодействие модулей УШ и модуля протокола RTP


Взаимодействие между модулями кодирования/декодирования речевых данных УШ и модулем протокола RTP осуществляется через память, которая находится в DSP модулей УШ. Внутри каждого модуля УШ выделяются следующие области памяти:

·для информации конфигурации и контроля работоспособности относительно модуля УШ;


·для управляющей информации;


·для данных (речевых и тонального сигнала) каждого КИ модуля УШ.


Информация конфигурации и контроля модуля УШ

телефония речевая информация модуль

Информация конфигурации служит для инициализации работы модуля УШ и записывается модулем протокола RTP перед запуском программы модуля УШ.

Информация конфигурации для модуля УШ включает:

Порядковый номер УШ (от 0 до 3) (1 байт);
Количество канальных интервалов в ИКМ, подключенном к УШ (32, 64…) (1 байт).
Информация контроля модуля УШ служит для контроля над ним со стороны модуля протокола RTP.
Информация контроля модуля УШ включает:
Признак готовности к работе модуля УШ после запуска (завершение инициализации) (2 бита):
00 - не готов;
11 - готов;



Примечание. Здесь и далее старший бит - левый.

Признак готовности записывается модулем УШ.

Признак выполнения модулем УШ ресинхронизации данных по причине обнаружения сбоя в синхронизации (РД):
0 - ресинхронизация не была выполнена;
1 - ресинхронизация была выполнена.



Управляющая информация, формируемая модулем протокола RTP

Управляющая информация, формируемая модулем протокола RTP, служит для управления работой модулей УШ.

Модулем протокола RTP формируется следующая информация:

1.информация, управляющая кодированием/декодированием данных речевого трафика, извлекаемых/передаваемых из/в КИ модулями УШ.


Управляющая информация, формируемая модулем УШ


Модуль УШ формирует для модуля протокола RTP информацию, управляющую номером области памяти при работе методом «пинг-понг». Номер области памяти может принимать два значения - 1 и 2, и определяет область памяти, в которую модуль протокола RTP должен записывать информацию (управляющая информация кодированием/декодированием, данные, извлеченные из пакетов RTP) или, из которой он должен считывать информацию (речевые данные, формируемые модулем УШ).


Данные, формируемые модулями УШ


Модуль УШ извлекает из всех КИ, участвующих в приеме и/или передаче речевого трафика, данные длительностью по 10 мс (определяется из информации управления кодированием/декодированием). Если в управляющей информации кодирования/декодирования для КИ установлен бит необходимости распознавания DTMF и акустических сигналов, модуль УШ выполняет распознавание этих сигналов (цифра DTMF, сигнал ЗАНЯТО и т.д.).

При наличии в канальном интервале тонального сигнала, речевые данные игнорируются до тех пор, пока не будет обнаружен конец передачи тонального сигнала.

Модули УШ преобразовывают речевые данные в формат в соответствии с управляющей информацией кодирования и помещают результат в соответствующую область данных. Байты речевых данных упорядочиваются в сетевом порядке.

Информация о распознанных тональных сигналах также записывается в соответствующую область памяти КИ для данных. При распознании сигнала (например, цифра DTMF, сигнал ЗАНЯТО), модуль УШ записывает данные распознанного сигнала в предназначенную для этого область памяти и устанавливает признак данных тонального сигнала в служебной информации. Так как поле длительности сигнала имеет размер в 2 байта, то максимальное значение длительности сигнала в единицах временной метки будет равно 64K, что соответствует 8,192 секундам. Поэтому, в случае, если сигнал длится более 8 секунд, модуль УШ устанавливает в служебной информации признак нового сигнала и продолжает отсчет длительности сначала.


Данные, формируемые модулем протокола RTP


Области памяти заполняются модулем протокола RTP данными, извлеченными из пакетов, поочередно, каждые 10мс, для всех КИ, участвующих в приеме и/или передаче речевого трафика.

Если пакет был потерян, то в бит признака данных, в количество байтов данных и в признак наличия данных тонального сигнала записывается 0;

Если был принят пакет с полезной нагрузкой CN, то в признак данных записывается 1, а количество байтов данных будет соответствовать размеру полезной нагрузки CN;

В случае отсутствия пакетов (тишина), в признак данных записывается 1, а в количество байтов 0.

Размер речевых данных соответствует интервалу 10 мс. Байты речевых данных упорядочиваются в сетевом порядке.

При получении пакетов с данными тональных сигналов модуль протокола RTP записывает их в соответствующую для КИ область памяти и устанавливает признак наличия данных тонального сигнала в служебную информацию. Длительность тонального сигнала соответствует длительности из принятого пакета. Если длительность (в единицах временной метки) превышает 10 мс, то данные тонального сигнала будут повторяться в областях данных необходимое количество интервалов в 10мс.

Задание


Разработать отдельные функции для класса интерфейса между модулем кодирования/декодирования речевых данных (УШ) и модулем протокола RTP. В частности:

основную потоковую функцию;

функцию считывания закодированных модулем УШ данных, и помещения их в циклический буфер накопления;

функцию предоставления данных из циклического буфера накопления по запросу другого потока;

функцию помещения другим потоком данных в циклический буфер воспроизведения для последующей записи их для декодирования в модуль УШ;

функцию записи в модуль УШ данных из циклического буфера воспроизведения.




Рис.1. Схема взаимодействия между модулем УШ и модулем протокола RTP


Модуль УШ и модуль протокола RTP входят в состав комплекса программ шлюза доступа IP.




Рис.2. Схема шлюза доступа IP


Модуль УШ и модуль протокола RTP - программы, работающие в разных процессорах Модуль УШ - в DSP процессоре. Модуль протокола RTP - в процессоре ARM или промышленном компьютере. Взаимодействие между модулями осуществляется через память, которая находится в DSP модулей УШ, при помощи интерфейса HPI (параллельный интерфейс). Операции чтения/записи выполняются посредством разработанных функций драйвера.

Основное назначение модуля УШ - кодирование/декодирование речевых данных. Модуль УШ обрабатывает речевые данные одного ИКМ (32 канальных интервала). Каждые 10 мс он кодирует входящий речевой поток тех каналов, которые ему задает модуль протокола RTP, и декодирует в обратном направлении. Используемые кодеки - G711, G726-16, G729.

Основное назначение модуля протокола RTP - упаковка закодированных речевых данных принятых из модуля УШ в пакеты RTP и отправка их в сеть IP, и, в обратном направлении - распаковка пакетов RTP, принятых из сети IP и предоставление данных для декодировании модулю УШ. Прием и запись речевых данных выполняется каждые 10 мс.


Реализация главного потока


#ifdef HAVE_CONFIG_H

#include

#endif

#include

#include

#include

#include

#include "UH_interface.h"

#include "servis.h"

#include "thread.h"namespace std;

t_UHInterface *pUHInterface[2];

// основная функция потока интерфейса УШ

void * main_UHInterface(void *arg)

{

unsigned char n=*(unsigned char*)arg;

pUHInterface[n]->run();

return NULL;

}main(int argc, char *argv[])

{

int ierr, i,n;

// t_UHInterface *pUHInterface[2];

t_thread *pUHInterfaceThread[2];

timespec sleeptimer;

// ========= параметры вывода ============

// биты 7 6 5 4 3 2 1 0

// -----------------------

// |di|do| | | | | | |

// -----------------------

// di - данные, принимаемые из DSP2 модуля УШ

// do - данные, передаваемые в DSP2 модуля УШ


//параметры вывода на консоль по умолчанию=0xc0;

// дополнительные параметры вывода

// для модуля УШ 0[DI]=0x00000001; // номеру бита установленному в 1 соответствует номер канала для вывода

ParamRtpPrint[DO]=0x00000001;

// для модуля УШ 1[DI+1]=0x00000001; // номеру бита установленному в 1 соответствует номер канала для вывода[DO+1]=0x00000001;

// это рекомендуется при использовании потоков реального времени

// locks all pages mapped into the address space of the calling

// process. This includes the pages of the code, data and stack segment,

// as well as shared libraries, user space kernel data, shared memory, and

// memory-mapped files. All mapped pages are guaranteed to be resident in

// RAM when the call returns successfully; the pages are guaranteed to

// stay in RAM until later unlocked.

if ((mlockall(MCL_CURRENT|MCL_FUTURE))==-1)

{ =errno;


fprintf(stderr,"mlockall() error! :\n %s errno=%i\n",strerror(ierr),ierr);

}

// создать объекты интерфейсов c УШ

for (n=0;n

{

// 32 - тип ИКМ тракта подведенного к модулю УШ (на 32 канальных интервала, м.б. на 64)

pUHInterface[n]= new t_UHInterface(n,32);(!pUHInterface[n])

{("t_RTPManager::Instance: Allocation memory error!\n");

exit(1);

}

}


// создать потоки интерфейсов c УШ

for (n=0;n

{

try

{ [n]->set_running(true);=n;[n] = new t_thread(main_UHInterface,

(void*)&i,SCHED_FIFO,49);

// SCHED_FIFO - тип планировщика, обслуживание по очереди, среди имеющих один приоритет

// 49 -приоритет, приоритеты должны быть

}

catch (int err)

{("!!UH Interface thread creating error, code = \n");


exit(1);

}

// сделать поток отсоединяемым.(он будет завершаться сам)[n]->detach();

// задержать перед созданием следующего потока, чтобы предыдущий успел запуститься

sleeptimer.tv_sec = 0;

sleeptimer.tv_nsec = 500000000; // 500ms(&sleeptimer, NULL);

}

pUHInterface[0]->StartDataAccumulation(0);bc[5]={0};

while (1)

{(bc, sizeof(bc), stdin);(bc[0]=='*') break;

}[0]->StopDataAccumulation(0);(n=0;n

{[n]->stop();(pUHInterfaceThread[n]);(pUHInterface[n]);

} ();

return EXIT_SUCCESS;

}

Реализация класса для взаимодействия модуля протоколя RTP и модуля УШ


#include

#include

#include

#include "api_6713b.h"

#include "UH_interface.h"

#include "servis.h"

#ifdef ___PC

#include "pcdata.h"

#endifconst char cName[16]="/dev/drv6713b. ";* pcCodec []={"null","G.711","G.726-16","G729"};SLineCtrl t_UHInterface::m_vzeroLineCtrl[32] = { {{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},

{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},

{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},

{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},

{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},{{0},0,0,0},

{{0},0,0,0},{{0},0,0,0},};


/**НАЗНАЧЕНИЕ : конструктор

* ВХОДНЫЕ ПАРАМЕТРЫ : ucUHNum - порядковый номер УШ (0-3),

* ucCINum - количество КИ в ИКМ

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/_UHInterface::t_UHInterface(unsigned char ucUHNum, unsigned char ucCINum)

{

//unsigned char i;

int i;

#ifdef ___PC

m_ucI=0;

#endif(m_cName, cName,sizeof(m_cName));

itoa(ucUHNum,(char*)(&m_cName[14]));_is_running=false;

m_bstop_running=false;_ucUHNum=ucUHNum;

m_ucCINum=ucCINum;_ucIndDI=DI+m_ucUHNum;

m_ucIndDO=DO+m_ucUHNum; _puiBaseAddress=(unsigned int*)(BASE_DATA_ADDRESS);

m_pvBaseDataCtrl=(SLineCtrl*)(m_puiBaseAddress+(CONF_SIZE>>2));

m_puiDumpNum=(unsigned int*)(m_pvBaseDataCtrl+64)+(sizeof(m_uiDumpNum)>>2);

m_puiBaseDataForRTP=m_puiDumpNum+(sizeof(m_uiDumpNum)>>2);

m_puiBaseDataForUH=m_puiBaseDataForRTP+(DUMP_SIZE*2>>2);

// глубина буфера воспроизведения

#ifdef ___PC

m_ucMaxPlayBackBufInd=JITTER_BUF_SIZE/10;

#else

m_ucMaxPlayBackBufInd=(JITTER_BUF_SIZE

#endif

// буфер воспроизведения для записи

m_pvPlayBackBuf=new SData[m_ucMaxPlayBackBufInd// буфер для всех 32 каналов


m_pvTmpPlayBackBuf=new SData[32];

// буфер для чтения данных речевого трафика из УШ

m_puiDataFromUH=new unsigned int[DUMP_SIZE>>2];

// буфер накопления данных речевого трафика, прочитанных из УШ для 32 КИ

m_pvAccumulatedData=new SData [ACCBUFF_DEPTH

{

printf("t_UHInterface::t_UHInterface: Allocation memory error!\n");

exit(1);

}

// проинициализировать буфер с управляющей информацией кодирования/декодирования

memset(m_vLineCtrl,0,sizeof(m_vLineCtrl));

// проинициализировать буфер с признаками изменения управляющей информации

// кодирования/декодирования

memset(m_uiChangeLineCtrl,0,sizeof(m_uiChangeLineCtrl));

// проинициализировать буфер с данными для УШ как отсутствие пакетов для всех КИ

// (тишина)

i=0;

while(i

{

ClearDataInPlayBackBuf(i++);

}


// обнулить буфер накопления данных речевого трафика

memset(m_pvAccumulatedData,0,ACCBUFF_DEPTH*32*sizeof(SData));(m_iAccGetInd,0,sizeof(m_iAccGetInd));

memset(m_iAccPutInd,0,sizeof(m_iAccPutInd));

memset(m_iAccIndDelta,0,sizeof(m_iAccIndDelta));

// обнулить массив с признаками необходимости накопления данных речевого трафика для 32 КИ

memset(m_IsAccumulating,0,sizeof(m_IsAccumulating));

#ifndef ___PC

// дескриптор устройства

m_devd=dsp6713b_open(m_cName);

if (m_devd

{

printf("!!t_UHInterface::run %i DSP2_open error, Res=%i, name=%s\n", m_ucUHNum,m_devd,m_cName);

exit(1);

}

#endif

}

/**НАЗНАЧЕНИЕ : деструктор

* ВХОДНЫЕ ПАРАМЕТРЫ : нет

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/_UHInterface::~t_UHInterface()

{

delete [] m_puiDataFromUH;

delete [] m_pvAccumulatedData;

delete [] m_pvPlayBackBuf;

delete [] m_pvTmpPlayBackBuf;

}

/**НАЗНАЧЕНИЕ : установить признак выполнения потока агента УШ

* ВХОДНЫЕ ПАРАМЕТРЫ : brunnung - значение признака выполнения потока

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/t_UHInterface::set_running(bool brunning)

{

m_is_running=brunning;

}

/**НАЗНАЧЕНИЕ : остановить поток агента УШ

* ВХОДНЫЕ ПАРАМЕТРЫ : нет

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/ t_UHInterface::stop(void)

{

timespec sleeptimer;

m_bstop_running=true;

while(m_is_running)

{

sleeptimer.tv_sec = 0;

sleeptimer.tv_nsec = 10000000; // 10 мс

nanosleep(&sleeptimer, NULL);

}


}

/**НАЗНАЧЕНИЕ: записать во внутреннюю память УШ данные конфигурации

* ВХОДНЫЕ ПАРАМЕТРЫ : ucCINum - количество КИ в ИКМ

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/t_UHInterface::WriteConfToUH(unsigned char ucCINum)

{

unsigned int uiConf;

#ifndef ___PC

int ires;

#endif=ucCINum;

uiConf

uiConf|=m_ucUHNum;(p_DOUT)

{("\n

}

#ifndef ___PC

// записать данные в память УШ при помощи интерфейса HPI

if ((ires=(dsp6713b_write(m_devd,(unsigned int)m_puiBaseAddress, uiConf))))

{

dsp6713b_reset(m_devd);b_close(m_devd);("\n!!t_UHInterface::WriteConfToUH %i: DSP2_write error!\n Addr=%08x Res=%i \n", m_ucUHNum,

(unsigned int)m_puiBaseAddress,ires);

exit(1);

}

#endif

}

/**НАЗНАЧЕНИЕ: задать накопление данных речевого трафика для КИ в буфере накопления

* ВХОДНЫЕ ПАРАМЕТРЫ : ucCI - номер канального интервала [0-31],

* ВЫХОДНЫЕ ПАРАМЕТРЫ: true - успешно

* false - ошибка: номер КИ > 31

*/t_UHInterface::StartDataAccumulation(unsigned char ucCI)

{(ucCI >31) return (false);_AccumulatedData.lock();_IsAccumulating[ucCI]=true;_AccumulatedData.unlock();(true);

}

/**НАЗНАЧЕНИЕ : прекратить накопление данных речевого трафика для КИ в буфере

* накопления

* ВХОДНЫЕ ПАРАМЕТРЫ : ucCI - номер канального интервала [0-31],

* ВЫХОДНЫЕ ПАРАМЕТРЫ: true - успешно

* false - ошибка: номер КИ > 31

*/t_UHInterface::StopDataAccumulation(unsigned char ucCI)

{(ucCI >31) return (false);_AccumulatedData.lock();_IsAccumulating[ucCI]=false;

// обнулить все индексы для циклических буферов

m_iAccGetInd[ucCI]=m_iAccPutInd[ucCI]=m_iAccIndDelta[ucCI]=_iPlayBackGetInd[ucCI]=m_iPlayBackPutInd[ucCI]=m_iPlayBackIndDelta[ucCI] = 0;_AccumulatedData.unlock();(true);

}

/**НАЗНАЧЕНИЕ: прочитать данные из внутренней памяти УШ и при необходимости

* поместить их в буфер накопления

* ВХОДНЫЕ ПАРАМЕТРЫ : нет

* ВЫХОДНЫЕ ПАРАМЕТРЫ: true - данные прочитаны,

* false - данные не прочитаны (в случае, если значение m_uiDumpNum

* некорректно)

*/t_UHInterface::GetDataFromUH(void)

{

unsigned int *puiAddress;

unsigned int uiSize,k;

#ifndef ___PC

int ires;

#endif

int i,j,n,ii;

unsigned char * pucData;buf1 [400];(!(m_uiDumpNum&0x03)) return (false);=m_puiBaseDataForRTP;

if (m_uiDumpNum==2) puiAddress+=DUMP_SIZE>>2;

#ifdef ___PC

// имитируем прием данных

i=0;

j=4;

while(i

{

if (m_IsAccumulating[i])

{

//CN-0,size-80

ucfromPCM0[j-4]=0x50;//20;

ucfromPCM0[j-1]=0;=0;

while (k

{

ucfromPCM0[j+k++]= m_ucI;

}

}


j=(++i)*84+4;

}

if (m_ucI(m_puiDataFromUH,(unsigned int*)ucfromPCM0,DUMP_SIZE);


#else

// прочитать данные при помощи интерфейса HPI

if((ires=(dsp6713b_read_IS(m_devd, (unsigned int)puiAddress, m_puiDataFromUH, DUMP_SIZE))))

{

dsp6713b_reset(m_devd);

dsp6713b_close(m_devd);

printf("\n!!t_UHInterface::GetDataFromUH %i: DSP2_read_IS error!\n Addr=%08x Res=%i \n", m_ucUHNum,

(unsigned int)puiAddress,ires);

exit(1);

}

#endif

for(i=31; i>=0; i--)

{

mtx_AccumulatedData.lock();(m_IsAccumulating[i])

{

n=m_iAccPutInd[i]

// помещаем данные в буфер накопления

m_pvAccumulatedData[i+n]= *((SData*)(m_puiDataFromUH)+i);

m_iAccPutInd[i]++; // увеличиваем значение индекса для следующего помещения данных(m_iAccPutInd[i]==ACCBUFF_DEPTH) m_iAccPutInd[i]=0; // циклический переход в начало_iAccIndDelta[i]++; // увеличиваем расстояние по отношению к индексу для извлечения

if (m_iAccIndDelta[i] > ACCBUFF_DEPTH)

{

// фиксируем состояние переполнения буфера накопления

printf("Acc buf overflow for %i \n",i);

}


}

mtx_AccumulatedData.unlock();

}((p_DIN) && (ParamRtpPrint[m_ucIndDI]))

{


snprintf(buf1,400,">>UH %i: %08x (%i)\n",m_ucUHNum,(unsigned int)puiAddress, m_uiDumpNum);

k=0x80000000;

for(i=31; i>=0; i--)

{

if (ParamRtpPrint[m_ucIndDI] & k)

{


uiSize=((SData*)(m_puiDataFromUH)+i)->m_vSDataCtrl.SpeachSize;

pucData=((SData*)(m_puiDataFromUH)+i)->m_ucData;(buf1,400," [%i] : CN-%01x, tone-%02x, size-%i\n",i,


((SData*)(m_puiDataFromUH)+i)->m_vSDataCtrl.CN,

((SData*)(m_puiDataFromUH)+i)->m_vSDataCtrl.Tone, uiSize);

printf(buf1);(uiSize)

{

buf1[0]='\0';(ii=0,j=0, n=0; (j

{(&buf1[ii],400," %02X", pucData[j]);+=3;((ii

}

printf(buf1);

}

}

k>>=1;

}

}


return(true);

}

/**НАЗНАЧЕНИЕ : поместить данные из буфера воспроизведения во внутреннюю память УШ

* ВХОДНЫЕ ПАРАМЕТРЫ : нет

* ВЫХОДНЫЕ ПАРАМЕТРЫ: true - данные записаны,

* false - данные не записаны (в случае, если значение m_uiDumpNum

* некорректно )

*/t_UHInterface::PutDataToUH(void)

{

unsigned int *puiAddress;

#ifndef ___PC

int ires;

#endif

int i, ii, j, n;

unsigned int uiSize,k;

unsigned char * pucData;

#ifdef ___PCInterval;MyTimeBegin, MyTimeEnd, MyDurTime;

#endif

char buf1 [400];

//printf("===RTP: PutDataToUH\n");(!(m_uiDumpNum&0x03)) return(false);

puiAddress=m_puiBaseDataForUH;

if (m_uiDumpNum==2) puiAddress+=DUMP_SIZE>>2; (i=31; i>=0; i--)

{

mtx_PlayBackBuf.lock();(m_iPlayBackIndDelta[i] > m_ucMaxPlayBackBufInd) // переполнение

{


while (m_iPlayBackGetInd[i] != m_iPlayBackPutInd[i])

{=m_iPlayBackGetInd[i]

m_iPlayBackIndDelta[i]--;

// циклический переход в начало буфера

if (m_iPlayBackGetInd[i] == m_ucMaxPlayBackBufInd) m_iPlayBackGetInd[i]=0;

}

}

else // нет данных

if (m_iPlayBackIndDelta[i] == 0)

{

m_pvTmpPlayBackBuf[i].m_vSDataCtrl.SpeachSize=0;

m_pvTmpPlayBackBuf[i].m_vSDataCtrl.Tone=0;

m_pvTmpPlayBackBuf[i].m_vSDataCtrl.CN=1;_PlayBackBuf.unlock();

continue;

}

n=m_iPlayBackGetInd[i]

m_pvTmpPlayBackBuf[i]=m_pvPlayBackBuf[i+n];

m_iPlayBackGetInd[i]++;

m_iPlayBackIndDelta[i]--;

// циклический переход в начало буфера

if (m_iPlayBackGetInd[i] == m_ucMaxPlayBackBufInd) m_iPlayBackGetInd[i]=0;_PlayBackBuf.unlock();

}

#ifndef ___PC

// записать данные при помощи интерфейса HPI

// пишем при помощи промежуточного буфера, чтобы не задерживать блокировку m_pvPlayBackBuf на время записи в DSP

if ((ires=(dsp6713b_write_IS(m_devd,(unsigned int)puiAddress, m_pvTmpPlayBackBuf, DUMP_SIZE))))

{

dsp6713b_reset(m_devd);b_close(m_devd);("\n!!t_UHInterface::PutDataToUH %i: DSP2_write_IS error!\n Addr=%08x Res=%i \n", m_ucUHNum,

(unsigned int)puiAddress,ires);

exit(1);

}

#endif ((p_DOUT) && (ParamRtpPrint[m_ucIndDO]))

{

printf("

//k=1;=0x80000000;(i=31;i>=0; i--)

{

if (ParamRtpPrint[m_ucIndDO] & k)

{=(m_pvTmpPlayBackBuf+i)->m_vSDataCtrl.SpeachSize;=(m_pvTmpPlayBackBuf+i)->m_ucData;(" [%i] : CN-%01x, tone-%02x, size-%i, newCtrl-%i\n",i,


(m_pvTmpPlayBackBuf+i)->m_vSDataCtrl.CN,

(m_pvTmpPlayBackBuf+i)->m_vSDataCtrl.Tone, uiSize,(m_pvTmpPlayBackBuf+i)->m_vSDataCtrl.NewLineCtrl);(uiSize)

{[0]='\0';(ii=0,j=0, n=0; (j

{(&buf1[ii],400," %02X", pucData[j]);+=3;((ii

}(buf1);

}

}>>=1;

}

}

return (true);

}

/**НАЗНАЧЕНИЕ : поместить данные КИ в буфер воспроизведения

* ВХОДНЫЕ ПАРАМЕТРЫ : ucCI - номер канального интервала [0-31],

* vSData - данные,

* ВЫХОДНЫЕ ПАРАМЕТРЫ: sizeof(Sdata) - успешное выполнение,

* 0 - данные не помещенны, т.к. буфер воспроизведения пустой

*-1 - номер КИ > 31

*/t_UHInterface::PutDataToPlayBackBuf(unsigned char ucCI, SData &vSData)

{

int n;

// printf("===RTP: PutDataToPlayBackBuf\n");(ucCI >31) return (-1);_PlayBackBuf.lock();


n=m_iPlayBackPutInd[ucCI]

// помещаем данные в буфер накопления

m_pvPlayBackBuf[ucCI+n]= vSData;

m_iPlayBackPutInd[ucCI]++; // увеличиваем значение индекса для следующего помещения данных(m_iPlayBackPutInd[ucCI]==m_ucMaxPlayBackBufInd) m_iPlayBackPutInd[ucCI]=0; // циклический переход в начало_iPlayBackIndDelta[ucCI]++; // увеличиваем расстояние по отношению к индексу для извлечения

if (m_iPlayBackIndDelta[ucCI] > m_ucMaxPlayBackBufInd)

{

// фиксируем состояние переполнения буфера воспроизведения

printf("PlayBack buf overflow for %i \n",ucCI);

}_PlayBackBuf.unlock();(sizeof(SData));

}

/**НАЗНАЧЕНИЕ : очистить буфер воспроизведения для КИ

* ВХОДНЫЕ ПАРАМЕТРЫ : ucCI - номер канального интервала [0-31],

* ВЫХОДНЫЕ ПАРАМЕТРЫ: true - успешно

* false - ошибка: номер КИ > 31

*/t_UHInterface::ClearDataInPlayBackBuf(unsigned char ucCI)

{(ucCI >31) return (false);_PlayBackBuf.lock();_pvTmpPlayBackBuf[ucCI].m_vSDataCtrl.SpeachSize=0;_pvTmpPlayBackBuf[ucCI].m_vSDataCtrl.Tone=0;_pvTmpPlayBackBuf[ucCI].m_vSDataCtrl.CN=1;_pvTmpPlayBackBuf[ucCI].m_vSDataCtrl.NewLineCtrl=0;_iPlayBackGetInd[ucCI]=0;_iPlayBackPutInd[ucCI]=0;_iPlayBackIndDelta[ucCI]=0;_PlayBackBuf.unlock();


return (true);

}

/**НАЗНАЧЕНИЕ : получить порцию данных из буфера накопления

* ВХОДНЫЕ ПАРАМЕТРЫ : ucCI - номер канального интервала,

* vSData - структура для помещения данных,

* ВЫХОДНЫЕ ПАРАМЕТРЫ: true - данные извлечены из буфера накопления,

* false - в буфере накопления нет данных

*/t_UHInterface::GetAccumulatedData(unsigned char ucCI, SData &vSdata)

{

int n;_AccumulatedData.lock();(m_iAccIndDelta[ucCI] > ACCBUFF_DEPTH) // переполнение

{

while (m_iAccGetInd[ucCI] != m_iAccPutInd[ucCI])

{_iAccGetInd[ucCI]++;_iAccIndDelta[ucCI]--;

// циклический переход в начало буфера

if (m_iAccGetInd[ucCI] == ACCBUFF_DEPTH) m_iAccGetInd[ucCI]=0;

}

}

else // нет данных

if (m_iAccIndDelta[ucCI] == 0)

{

mtx_AccumulatedData.unlock();

return (false);

}

n=m_iAccGetInd[ucCI]

vSdata=m_pvAccumulatedData[ucCI+n];

m_iAccGetInd[ucCI]++;

m_iAccIndDelta[ucCI]--;

// циклический переход в начало буфера

if (m_iAccGetInd[ucCI] == ACCBUFF_DEPTH) m_iAccGetInd[ucCI]=0;_AccumulatedData.unlock();(true);

}

/**НАЗНАЧЕНИЕ : записать управляющую информацию кодирования/декодирования во

* внутреннюю память модуля УШ для тех КИ, у которых она изменилась

* ВХОДНЫЕ ПАРАМЕТРЫ : нет

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/ t_UHInterface::WriteLineCtrlToUH(void)

{

//unsigned char i;

int i;

unsigned int k;

#ifndef ___PC

int ires;

#endif

SLineCtrl *pvDataCtrl;

// прочитать из внутренней памяти УШ номер области памяти для

// считывания и записи данных модулем протокола RTP

#ifdef ___PC

m_uiDumpNum=1;

#else

// прочитать номер области памяти

if ((ires=(dsp6713b_read(m_devd,(unsigned int)m_puiDumpNum, &m_uiDumpNum))))

{

dsp6713b_reset(m_devd);b_close(m_devd);("\n!!t_UHInterface::GetDumpNum %i: DSP2_read error!\n Addr=%08x Res=%i \n", m_ucUHNum,

(unsigned int)m_puiDumpNum,ires);(1);

}

#endif

// printf("%i\n",m_uiDumpNum);

if (!(m_uiDumpNum&0x03))

{

printf("\n!!>>UH %i: DumpNum %08x > %08x\n",m_ucUHNum, (unsigned int)m_puiDumpNum,m_uiDumpNum);

return;

}

// выполнить запись управляющей информации (не взодит в задание)

}

/**НАЗНАЧЕНИЕ : очистить управляющую информацию всех КИ во внутренней памяти

* модуля УШ

* ВХОДНЫЕ ПАРАМЕТРЫ :

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/ t_UHInterface::ClearLineCtrlInUH(void)

{

unsigned int uiAddress1, uiAddress2;

#ifndef ___PC

int ires;

#endif=uiAddress2=(unsigned int)m_pvBaseDataCtrl;// адрес области памяти #1

uiAddress2+=sizeof(m_vLineCtrl); // адрес области памяти #1_LineCtrl.lock();(m_vLineCtrl,0,sizeof(m_vLineCtrl));_LineCtrl.unlock();

#ifndef ___PC

// m_vzeroLineCtrl используем, чтобы не задерживать блокировку m_vLineCtrl на время записи в DSP

if ((ires=(dsp6713b_write_IS(m_devd,uiAddress1, (void*)m_vzeroLineCtrl, sizeof(m_vzeroLineCtrl)))) ||

(ires=(dsp6713b_write_IS(m_devd,uiAddress2, (void*)m_vzeroLineCtrl, sizeof(m_vzeroLineCtrl)))) )

{

dsp6713b_reset(m_devd);

dsp6713b_close(m_devd);

printf("\n!!t_UHInterface::ClearLineCtrlInUH %i: DSP2_write_IS error!\n Addr=%08x Res=%i \n", m_ucUHNum,uiAddress1,ires);

exit(1);

}

#endif

}

/**НАЗНАЧЕНИЕ : запуск модуля УШ (инициализация модуля УШ и запуск программы в DSP)

* ВХОДНЫЕ ПАРАМЕТРЫ : нет

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/t_UHInterface::StartWorkDSP2(void)

{

unsigned int uiConf;

unsigned int ii;

int i,ires;

timespec SleepTime;

#ifndef ___PC

// сбросить DSP модуля УШ

if((ires=(dsp6713b_reset(m_devd))))

{b_close(m_devd);("!!t_UHInterface::StartWorkDSP2 %i DSP2_reset error, Res=%i\n", m_ucUHNum,ires);

exit(1);

}

// записать в УШ данные конфигурации (m_ucCINum);(); // обнулить управляющую информацию в памяти модуля УШ по всем КИ

// проинициализировать в УШ области памяти для данных

m_uiDumpNum=1;();_uiDumpNum=2;();((ires=(dsp6713b_start(m_devd))))

{b_close(m_devd);("!!t_UHInterface::StartWorkDSP2 %i DSP2_start error, Res=%i\n", m_ucUHNum,ires);(1);

}

//! ждать готовность УШ

for (i=MAX_WAIT_READY; i>0; i--) // 10 раз = 100 ms

{


if((ires=(dsp6713b_read(m_devd,(unsigned int)m_puiBaseAddress, &uiConf))))

{b_reset(m_devd);b_close(m_devd);("!!t_UHInterface::StartWorkDSP2 %i: DSP2_read error!\n Addr=%08x Res=%i \n",_ucUHNum,(unsigned int)m_puiBaseAddress,ires);(1);

}((uiConf & 0xC0) == 0xC0)

{("UH %i is READY!\n",m_ucUHNum);;

}

} (i

{("UH %i is NOT READY!\n", m_ucUHNum);b_reset(m_devd);b_close(m_devd);(1);

}

#else("UH %i is READY!\n",m_ucUHNum);

#endif

}

/**НАЗНАЧЕНИЕ : исполнительный метод потока интерфейса УШ

* ВХОДНЫЕ ПАРАМЕТРЫ : нет

* ВЫХОДНЫЕ ПАРАМЕТРЫ: нет

*/t_UHInterface::run(void)

{

#ifndef ___PC

unsigned int ii;

int ires;

#endifSleepTime;("UH_Interface %i is started\n",m_ucUHNum);

// сбросить DSP и загрузить программу модуля УШ

StartWorkDSP2();

#ifndef ___PC

ires=dsp6713b_getHPIC(m_devd,&ii);

// работа с управляющими регистрами DSP

// сбросить HINT и установить DSPINT, чтобы DSP начал выставлять прерывания

ires=dsp6713b_setHPIC(m_devd,ii|0x00000002);

#endif

{


if (m_bstop_running) break;

#ifndef ___PC

dsp6713b_sleep(m_devd); // выход из этой функции происходит каждые 10 мс по прерыванию от DSP

// обработчик прерываний находится в драйвере, драйвер инициирует этот выход

#endif

// записать управляющую информацию,во внутреннюю память модуля УШ для тех КИ, у которых она изменилась

// (упр.информация меняется по запросу другого потока)

// // здесь же определяется номер области памяти для

// считывания и записи данных модулем протокола RTP

WriteLineCtrlToUH();

// прочитать данные из внутренней памяти УШ и при необходимости

// поместить их в буфер накопления

// здесь же определяется номер области памяти для

// считывания и записи данных модулем протокола RTP

GetDataFromUH();

//поместить данные из буфера воспроизведения во внутреннюю память УШ

PutDataToUH();

#ifdef ___PC

SleepTime.tv_sec = 0;

SleepTime.tv_nsec = 5000000;//5 мс

nanosleep(&SleepTime, NULL);


#endif

} while(1);

#ifndef ___PC

// сбросить DSP

if((ires=(dsp6713b_reset(m_devd))))

{

dsp6713b_close(m_devd);

printf("!!t_UHInterface::run %i DSP2_reset error, Res=%i\n", m_ucUHNum,ires);

exit(1);

}

else dsp6713b_close(m_devd);

printf("\n RTP: DSP device is closed\n");

#endif

("Агент UH: UHInterface % is stopped\n",m_ucUHNum);

m_is_running=false;

}


Заключение


В ходе выполнения задания в период прохождения производственной практики было проведено ознакомление с принципами организации и работы IP-телефонии, а также передачи голосового сигнала.

Были реализованы отдельные функции для класса интерфейса между модулем кодирования/декодирования речевых данных (УШ) и модулем протокола RTP. В частности:

·основная потоковая функция;


·функция считывания закодированных модулем УШ данных, и помещения их в циклический буфер накопления;


·функция предоставления данных из циклического буфера накопления по запросу другого потока;


·функция помещения другим потоком данных в циклический буфер воспроизведения для последующей записи их для декодирования в модуль УШ;


·функция записи в модуль УШ данных из циклического буфера воспроизведения.


Программный код был успешно протестирован и включен в интерфейс, обеспечивающий взаимодействие между модулем кодирования/декодирования речевых данных (УШ) и модулем протокола RTP.


Список литературы:


1. Руководство по технологиям объединенных сетей, 4-е издание.: Пер. с англ. - М.: Издательский дом «Вильямс», 2005.

2. Гольдштейн B.C., Пинчук А.В., СуховицкийА.Л. IP-Телефония. - М.: Радио и связь, 2001.

3. Цимберов А.Г. Учебник по IP-телефонии. М.: Харвест, 2002г.

4. www.tec.voip-list.net


Не сдавайте скачаную работу преподавателю!
Данный отчет по практике может быть использован Вами как образец, в соответсвтвии с примером, но с данными своего предприятия, Вы легко сможете написать отчет по своей теме.

Другие материалы:
Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем отчёт по практике самостоятельно:
! Отчет по ознакомительной практике В чем заключается данный вид прохождения практики.
! Отчет по производственной практики Специфика и особенности прохождения практики на производстве.
! Отчет по преддипломной практике Во время прохождения практики студент собирает данные для своей дипломной работы.
! Дневник по практике Вместе с отчетам сдается также дневник прохождения практики с ежедневным отчетом.
! Характеристика с места практики Иногда преподаватели требуеют от подопечных принести лист со словесной характеристикой работы студента, написанный ответственным лицом.

Особенности отчётов по практике:
по экономике Для студентов экономических специальностей.
по праву Для студентов юридических специальностей.
по педагогике и психологии Для студентов педагогических и связанных с психологией специальностей.
по строительству Для студентов специальностей связанных со строительством.
технических отчетов Для студентов технических специальностей.
по информационным технологиям Для студентов ИТ специальностей.
по медицине Для студентов медицинских специальностей.