LINUX.ORG.RU

История изменений

Исправление zaz, (текущая версия) :

fwrite(audioData, strlen(audioData), 1, output);

strlen здесь вообще ни к чему, здесь строк нету реальный размер аудио данный в пакете это (len - sizeof(RtpHdr)); тоесть код должен быть

fwrite(audioData, (len - sizeof(RtpHdr)), 1, output);
Также при записи usleep явно лишний, recvfrom будет ожидать пакета если его нету (при блокируещем IO), а с usleep можно получить переполнение буфера и потерю данных. + не хватает обработки ошибок (тогоже recfrom и fwrite), но вобщем с таким кодом можно получить аудио данные хотя они скорее всего будут немного испорчены (из за strlen в fwrite), иногда этот код может приводить к сегфолту по тойже причине (вам явно не хватает практики работы с С).

Чтение и отправка выглядит ужасно :), он не понятно что делает но явно не занимается отправкой аудио в RTP. Должно быть чтото вроде этого (код не проверяю поэтому может и не скомпилируется):

// Новая структура для RTP с PCMA/PCMU данными
#pragma pack(push, 1)
struct RTP_PCMA
{
   struct RtpHdr hdr;
   char audioData[160];
};
#pragma pack(pop)
// .....

struct RTP_PCMA outPacket;
int ts = 0, seq = 0, ssrc = 1000000000;
srand(time(NULL)); // srand нужно вызывать ДО rand иначе от него толку 0
ssrc += rand()%8999999999;

// Заполняем поля заголовка которые не меняются для всего потока
outPacket.hdr.version = 2;
outPacket.hdr.p       = 0;
outPacket.hdr.x       = 0;
outPacket.hdr.cc      = 0;
outPacket.hdr.m       = 0;
outPacket.hdr.pt      = 8;
outPacket.hdr.ssrc = htonl(ssrc);

while (!feof(output)) {
   fread(outPacket.audioData, 160, 1, output);
   ts += 160;
   outPacket.hdr.seq = htons(++seq);
   outPacket.hdr.ts  = htonl(ts);
		
   sendto(s1, &outPacket, sizeof(outPacket), 0, (struct sockaddr *) &si_other, slen);
   usleep(19500);
}
Вот както так, но сдесь есть есще нюанс с usleep, как вы могли заметить я там поставил 19500 вместо 20000 - связано с тем что помимо самого usleep есть есще накладные расходы на чтение и отправку и их нужно учитывать (лутше отправлять пакеты чаще чем реже). Но 19500 тоже не решение проблемы - сдесь нужно делать собственный контроль по времени (по средствам clock_gettime(CLOCK_MONOTONIC, &ts) ). Тоесть usleep используете исключительно для того чтоб «убить» время, и скажем засыпаете на 10 милисекунд (вместо 20). Но на каждой итерации цыкла через clock_gettime(CLOCK_MONOTONIC, &ts) проверяете сколько прошло времени после последней отправки RTP пакета, если меньше 20 милисекунд - то ничего не делаете если же больше то отправляете такое ко-во пакетов сколько нужно (например если прошло 40 милисекунд то отправляете сразу 2 пакета). Но для начала попробуйте с usleep(19500) - должно быть более мение приемлимо, потом уже можно будет усовершенствовать ...

Исходная версия zaz, :

fwrite(audioData, strlen(audioData), 1, output);

strlen здесь вообще ни к чему, здесь строк нету реальный размер аудио данный в пакете это (len - sizeof(RtpHdr)); тоесть код должен быть

fwrite(audioData, (len - sizeof(RtpHdr)), 1, output);
Также при записи usleep явно лишний, recvfrom будет ожидать пакета если его нету (при блокируещем IO), а с usleep можно получить переполнение буфера и потерю данных. + не хватает обработки ошибок (тогоже recfrom и fwrite), но вобщем с таким кодом можно получить аудио данные хотя они скорее всего будут немного испорчены (из за strlen в fwrite), иногда этот код может приводить к сегфолту по тойже причине (вам явно не хватает практики работы с С).

Чтение и отправка выглядит ужасно :), он не понятно что делает но явно не занимается отправкой аудио в RTP. Должно быть чтото вроде этого (код не проверяю поэтому может и не скомпилируется):

// Новая структура для RTP с PCMA/PCMU данными
#pragma pack(push, 1)
struct RTP_PCMA
{
   struct hdr;
   char audioData[160];
};
#pragma pack(pop)
// .....

struct RTP_PCMA outPacket;
int ts = 0, seq = 0, ssrc = 1000000000;
srand(time(NULL)); // srand нужно вызывать ДО rand иначе от него толку 0
ssrc += rand()%8999999999;

// Заполняем поля заголовка которые не меняются для всего потока
outPacket.hdr.version = 2;
outPacket.hdr.p       = 0;
outPacket.hdr.x       = 0;
outPacket.hdr.cc      = 0;
outPacket.hdr.m       = 0;
outPacket.hdr.pt      = 8;
outPacket.hdr.ssrc = htonl(ssrc);

while (!feof(output)) {
   fread(outPacket.audioData, 160, 1, output);
   ts += 160;
   outPacket.hdr.seq = htons(++seq);
   outPacket.hdr.ts  = htonl(ts);
		
   sendto(s1, &outPacket, sizeof(outPacket), 0, (struct sockaddr *) &si_other, slen);
   usleep(19500);
}
Вот както так, но сдесь есть есще нюанс с usleep, как вы могли заметить я там поставил 19500 вместо 20000 - связано с тем что помимо самого usleep есть есще накладные расходы на чтение и отправку и их нужно учитывать (лутше отправлять пакеты чаще чем реже). Но 19500 тоже не решение проблемы - сдесь нужно делать собственный контроль по времени (по средствам clock_gettime(CLOCK_MONOTONIC, &ts) ). Тоесть usleep используете исключительно для того чтоб «убить» время, и скажем засыпаете на 10 милисекунд (вместо 20). Но на каждой итерации цыкла через clock_gettime(CLOCK_MONOTONIC, &ts) проверяете сколько прошло времени после последней отправки RTP пакета, если меньше 20 милисекунд - то ничего не делаете если же больше то отправляете такое ко-во пакетов сколько нужно (например если прошло 40 милисекунд то отправляете сразу 2 пакета). Но для начала попробуйте с usleep(19500) - должно быть более мение приемлимо, потом уже можно будет усовершенствовать ...