• Advertisement

Archived

This topic is now archived and is closed to further replies.

Cannot transfer a wave-file over a socket?!?

This topic is 5548 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I cannot get this to work. I am simply trying to transfer a wave file over a client/server connection using winsock! Its kinda weird because I am reading the file into a char* buffer at the server side, splitting it into chunks and transferring one at the time. Just to check, I also save those chunks to a file as I send them out on the socket. That file works just fine, but the file stored at the client side is corrupt... opening it up in a textviewer it looks pretty much the same, but is missing a few symbols here and there... The weird thing is that I am using exactly the same datatypes and sizes for the buffers, fileformats and so on on both sides, so I have no Idea what causes the data to go bad during the process... any ideas? I have the sourcecode at my site in case you have an idea what I am doing wrong: http://groups.msn.com/californiacornboy/Documents/Files/StreamCasterInternetRadio.zip Thanks again for all your time, you have been a great help! "That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
Advertisement
Can''t download that unless you have an MSN Passport. I have one but it doesn''t work with my browser of choice. Can I suggest you find some other storage space, or perhaps post some code here? I can''t imagine your sending and receiving code would be too long.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files | My stuff ]

Share this post


Link to post
Share on other sites
Does the ''anomaly'' happen at certain intervals? Do they corespond with the lenght of the chunks you split the file?

Share this post


Link to post
Share on other sites
i cant see a pattern no, I have cleaned up my code, and it seems that it works for smaller files, but when they get larger, data gets corrupted, and chunks are lost even over TCP! I tried slowing down the sending, but that didnt help either...

"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
So you save it to a file at the receiving end... is that file the same size as the file that you sent?

Are you checking how many bytes send() and recv() actually did send? You may have told them to send/recv say 8192 bytes or whatever but that doesn''t mean they actually did.

I suggest you try sending a text file first. Fill this text file with text that will immediately be obvious if it wasn''t received properly, ie. something like:

ABCDEFGHIJKLMNOPQRSTUVWXYZ012345679
ABCDEFGHIJKLMNOPQRSTUVWXYZ012345679
ABCDEFGHIJKLMNOPQRSTUVWXYZ012345679
ABCDEFGHIJKLMNOPQRSTUVWXYZ012345679
ABCDEFGHIJKLMNOPQRSTUVWXYZ012345679
....

Viewing the received version of this will give you a much clearer idea of what''s going on than looking at raw wav data
(You might need to make the text file very large to have a better chance of bringing up the same errors you had with the wav file.)

Share this post


Link to post
Share on other sites
Yeah thats a good idea! Thanks...
Well, it appears that there is no garble actually - but once I start sending files over a certain size, packets are lost. Files of size up to 90Kb work, but more than that no...

I send chunks of 128 bytes at a time, and count how many of these the client receive. The server might send something like 135 chunks, while the client only counts 134. For even bigger files, more chunks are lost. The number of lost chunks is consistent for every run of the program with the same file, though.... I also tried to change buffersize. Running with chunksize 8, I sent 21387 chunks but received only 21319. Thats 68 lost chunks * 8 = 544bytes that TCP lost? That is a lot for a guaranteed-delivery service like TCP isnt it? I have also tried to slow down my program in order to give the CPU, HD and network more time to see if that helped avoiding the errors, but it didnt help.



"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
It is most likely a problem with your code. TCP/IP doesn''t lose packets.

Try posting some of your send/recv code.

Share this post


Link to post
Share on other sites
Awesome, I really appreciate it! I know how demanding it can be to go through someone else''s code.

This problem is so confusing and frustrating to me, and I''ve worked my ass off trying to find the source of the instability.

"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
OK heres my source-code for the client side:

#include <windows.h> // for winsock functions
#include <stdio.h> // for printf()
#include <string.h> // for strcopy()
#include <stdlib.h> // for atoi() and other helpfunctions
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <Dmusici.h>
#include "dxutil.h"
#include
#include
#include
using namespace std;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DEFINITIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define domainAF AF_INET // Address Family = Internet
#define protocol 0 // set to 0 to use default protocol for chosen domain and type

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int TCPSocket, // ID for socket to communicate through
UDPSocket;
struct hostent *remoteInfo; // temp storage for IP
struct sockaddr_in remoteAddress; // stores address info for remote
int addressLength;
struct in_addr remoteIP; // IP address for remote

bool listening;
char *nickName;
int READBUFFERSIZE;
int HEADERSIZE;
int j; // used for clearing out strings
ofstream audioCache("audiocache.wav",ios::out|ios::binary|ios::ate);
HWND hWndAudio;
IDirectMusicLoader8 *pLoader = NULL;
IDirectMusicPerformance8 *pPerformance = NULL;
IDirectMusicSegment8 *pSound = NULL;
bool TCPMODE;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION PROTOTYPES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void connectTo ( const char*, const int );
void getAudio ( void );
HRESULT hrInitDirectAudio ( HWND );
HRESULT hrLoadSound ( char* );
HRESULT hrPlaySound ( IDirectMusicSegment8* );
void vShutdownDirectAudio ( void );

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CONNECT TO SERVER
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void connectTo(const char *remoteName, const int remotePort){
char *programInfo; // 1024 with zero fill, msgformat from server
char *headerData; // 128 with zero fill, msgformat from server
char *choice; // 1 for TCPMODE, 2 for UDPMODE

// Attempt to create a socket for communication
if ((TCPSocket = socket(domainAF, SOCK_STREAM, protocol)) < 0){
printf("*** System unable to create TCP socket ***\n");
exit(1);
}
if ((UDPSocket = socket(domainAF, SOCK_DGRAM, protocol)) < 0){
printf("*** System unable to create UDP socket ***\n");
exit(1);
}

// Attempt to lookup IP address for remote
remoteInfo = gethostbyname(remoteName);
if (remoteInfo == NULL){
printf("*** Could not get remote IP ***\n");
exit(1);
} else memcpy(&remoteIP, remoteInfo->h_addr, 4);

// Fill in data about remote address
remoteAddress.sin_family = domainAF;
remoteAddress.sin_port = htons(remotePort); // convert 16-bit values between host and network byte order
remoteAddress.sin_addr.s_addr = inet_addr(inet_ntoa(remoteIP));

choice = new char[1];
choice[0] = 0;
printf("Select 1 : TCP MODE\n 2 : UDP MODE : ");
scanf ("%s", choice); // read userid from keyboard into userID
if(!strcmp(choice,"1")){
printf(" TCPMODE Enabled\n");
TCPMODE = true;
}
else if(!strcmp(choice,"2")){
printf(" UDPMODE Enabled\n");
TCPMODE = false;
}
else{printf("*** ILLEGAL CHOICE ***"); exit(1);}

printf ("Nickname : ");
nickName = new char[30];
for(j=0; j<30; j++)
{
nickName[j] = 0;
}
scanf ("%s", nickName); // read userid from keyboard into userID

// Initiate connection-oriented communication ( blocking call connect() )
if ( connect( TCPSocket, (struct sockaddr *)&remoteAddress, sizeof(remoteAddress) ) != 0){
printf("*** System unable to connect - no TCP server ***\n");
exit(1);
}
printf("\n");
printf("-=Radio %s=- at %s, port %d\n", remoteName, inet_ntoa(remoteIP), remotePort);

send( TCPSocket, nickName, 30, 0 ); // sends outbuffer to server using TCP
send( TCPSocket, choice, 1, 0 );
programInfo = new char[READBUFFERSIZE+1]; for(j=0; j headerData = new char[HEADERSIZE+1]; for(j=0; j recv( TCPSocket, programInfo, READBUFFERSIZE, 0 );
recv( TCPSocket, headerData, HEADERSIZE, 0 );
//printf("RECEIVED HEADERDATA: %s\n",headerData);
printf("%s\n",programInfo);
char inBuffer[20];
char outBuffer[20];
strcpy(outBuffer,"OK");
memset ( inBuffer, ''\0'', sizeof(inBuffer) ); //clears out inbuffer before use
addressLength = sizeof(remoteAddress);
sendto( UDPSocket, outBuffer, 19, 0,
(struct sockaddr *)&remoteAddress, addressLength ); // sends outbuffer to server using UDP
recvfrom( UDPSocket, inBuffer, 19, 0,
(struct sockaddr *)&remoteAddress, &addressLength);

// Receive headerinfo for wavefile
audioCache.write(headerData,HEADERSIZE);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// INIT AUDIOSYSTEM USING DIRECTX
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT hrInitDirectAudio(HWND hWnd){
HRESULT hResult;
IDirectMusicAudioPath8 *path;

// Init COM - all DirectAudio functions are COM-based
CoInitialize(NULL);

// Create Loader-interface, store it in pLoader
hResult = CoCreateInstance( CLSID_DirectMusicLoader,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicLoader8,
(void**)&pLoader );
if (FAILED(hResult)){ printf("*** DX8 Cant create Loader\n"); return(NULL);}

// Create Performance-interface, store it in pPerformance
hResult = CoCreateInstance( CLSID_DirectMusicPerformance,
NULL,
CLSCTX_INPROC,
IID_IDirectMusicPerformance8,
(void**)&pPerformance );
if (FAILED(hResult)){ printf("*** DX8 Cant create Performance\n"); return(NULL);}

// Initalize Audio in the performance interface
hResult = pPerformance->InitAudio( NULL, // NULL=internal IDirectMusic8 interface created
NULL, // NULL=internal IDirectSound8 interface created
hWnd, // Handle to Window using this sound-system
DMUS_APATH_DYNAMIC_STEREO, // Type of default path
4, // # Performance-channels
DMUS_AUDIOF_ALL, // This flag includes all flags:
// * DMUS_AUDIOF_STREAMING - allows streaming WAVE files!
// * DMUS_AUDIOF_BUFFERS - use multiple buffers
// * DMUS_AUDIOF_ENVIRON - use environmental modeling
// * DMUS_AUDIOF_EAX - use EAX effects
// * DMUS_AUDIOF_3D - allow 3D buffers
NULL ); // Default DMUS_AUDIOPARAM structure used
if (FAILED(hResult)){ printf("*** DX8 Cant init audio\n"); return(NULL);}

// Retrieve default audio path - used for playing sounds
if (FAILED( pPerformance->GetDefaultAudioPath(&path))){ printf("*** DX8 Cant get default audio-path\n"); return(NULL);}

// Set default volume for the playback-path
if (FAILED( path->SetVolume(0, // Volume 0 = full volume, in the range [0..-9600]
0) // Duration in milliseconds for volume-change. 0 = immediate.
)){ printf("*** DX8 Cant set path volume\n"); return(NULL);}
return (S_OK);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// LOAD SOUND WAVE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT hrLoadSound( char *szFileName){
WCHAR wstrFileName[256];
DXUtil_ConvertGenericStringToWide( wstrFileName, szFileName ); // Unicode conversion

// Check if DSound is Initialized OK
if ( !pLoader || !pPerformance ){ printf("*** DX8 not initialized\n"); return(NULL);}

// Clean up sound if it already exists
if ( pSound ){
pSound->Unload( pPerformance );
pSound->Release();
pSound = NULL;
}

// Load sound resource from file and place it in segment
if (FAILED( pLoader->LoadObjectFromFile( CLSID_DirectMusicSegment, // Object-type to load
IID_IDirectMusicSegment8, // Interface ID
wstrFileName, // Filename for sound-file
(LPVOID*) &pSound // Stores loaded object
))){ printf("*** DX8 Cant load file\n"); return(NULL);}
// Download the data - transfer it to performance interface that play sounds
if (FAILED( pSound->Download( pPerformance))){ printf("*** DX8 Cant download file\n"); return(NULL); }
return(S_OK);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PLAYSOUND WAVE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT hrPlaySound(IDirectMusicSegment8 *pSegment){
// Check if DSound is Initialized OK
if ( !pSegment || !pPerformance ){ printf("*** DX8 not initialized\n"); return(NULL);}

// Play segment
if(FAILED( pPerformance->PlaySegmentEx(
pSegment, // Segment-source to play
NULL, // Segment-name - not implemented in DX8
NULL, // Transition-object to associate with playback
DMUS_SEGF_DEFAULT | DMUS_SEGF_SECONDARY, // Flags! Secondary buffer can play several simultaneously
0, // Starttime 0 - starts playing sound immediately
NULL, // IDirectMusicSegmentState8 state pointer for playback
NULL, // audiopath/segmentstate to stop when this segment starts playing
NULL // Audiopath. NULL = default.
))){ printf("*** DX8 Cant playback soundfile\n"); return(NULL); }
return(S_OK);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLEAN UP DIRECTAUDIO
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void vShutdownDirectAudio( void ){
if ( pLoader ){
pLoader->Release();
pLoader = NULL;
}
if ( pPerformance ){
pPerformance->Release();
pPerformance = NULL;
}
if ( pSound ){
pSound->Unload( pPerformance ); // Required for all downloaded segments into performance objects
pSound->Release();
pSound = NULL;
}
CoUninitialize();
}

void closeConnection( void ){
closesocket(TCPSocket);
closesocket(UDPSocket);
WSACleanup();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GET AUDIO STREAM
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Should run in own thread
void getAudio( void ){
char *soundData; // 128 with zero fill, msgformat from server
int audioBytesRead,
totalBytesRead,
chunksRead;
listening = true;
printf("Receiving broadcast sound-data\n[");
chunksRead = totalBytesRead = 0;
while (listening==true){
soundData = new char[READBUFFERSIZE+1];
for(j=0; j {
soundData[j] = 0;
}
if(TCPMODE) audioBytesRead = recv( TCPSocket, soundData, READBUFFERSIZE, 0 );
else audioBytesRead = recvfrom( UDPSocket, soundData, READBUFFERSIZE, 0,
(struct sockaddr *)&remoteAddress, &addressLength);
totalBytesRead += audioBytesRead;
//if (audioBytesRead > 0){
//if(TCPMODE) printf("t"); else printf("u");
if( soundData[0] == ''E''){ // Server sends message containing "EOP" when radio-program is finished
if( soundData[1] == ''O''){
if( soundData[2] == ''P''){
//printf("\n%s - Shutting Down\n",soundData);
listening = false;
}
}
}
else{
chunksRead++;
// Append wave-data to file
audioCache.write(soundData,READBUFFERSIZE);
}
// Play sounddata after caching enough data

//}
}
printf("] %d chunks read.\n",chunksRead);
audioCache.close();
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MAIN
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]){
WORD wVersionRequested = MAKEWORD(1,1);
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);
char temp[1];
printf("\n<<< Winsock Radio Stream Client >>>\n (C) 2002 Trond Borg\n\n");
hrInitDirectAudio(hWndAudio);
READBUFFERSIZE = 128;
HEADERSIZE = 128;
if (argc != 3){
connectTo("z8n", 888);
}
else connectTo( argv[1], atoi(argv[2]) );
getAudio();
closeConnection();
printf("Audio broadcast finished\n");
hrLoadSound("audiocache.wav");
hrPlaySound(pSound);
vShutdownDirectAudio();
scanf ("%s",temp);
return(1);
}//END MAIN

"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
...and heres the server-code:
(THANKS AGAIN ALL)
#include // for printf()
#include // for atoi() and other helpfunctions
#include // for socket functions
#include //
#include // for generating timestamp time()
#include //
#include //
#include //
#include // for strncopy() etc
#include //
#include //
#include //
#include //
using namespace std; ///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define DOMAIN_AF AF_INET // Address Family = Internet
#define PROTOCOL 0 // set to 0 to use default protocol for chosen domain and type
#define MAXQUEUE 3 // Max 3 pending connections
#define MAXCLIENTS 3 //
#define SENDBUFFERSIZE 128 ///
#define HEADERSIZE 128 ////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct broadcast{
char *headerData;
long headerSize;
char *audioData;
long byteSize,
bytesSent,
bytesLeft;
char *programInfo; // Text string sent to clients logging on to the show, info about the wav being broadcasted
bool done; // Indicates that all data has been broadcasted
};

struct client{
char *nickName;
struct sockaddr_in address; // stores address info for remote
struct hostent *Info; // temp storage for retreiving IP
struct in_addr IP; // IP address for remote
int addressLength;
int socket_fd;
bool connected;
bool TCPMODE; // True for TCP, false for UDP

};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct broadcast broadCast; //
struct waveChunk waveData[]; //
u_short servePort;
struct client clients[MAXCLIENTS];// Stores all clients in an array
int numberOfClients; //
int numberOfChunks; //
FILE *logFile; // filepointer for logging broadcasts and listeners
timeval timeout; //
//
struct sockaddr_in localAddress; // stores address info for remote
struct hostent *localInfo; // temp storage for retreiving IP
struct in_addr localIP; // IP address for remote
char *localHostName; // Name for server
int j; // used for clearing out strings
int TCPSocket; // ID for socket to listen on for requests and send TCP traffic
int UDPSocket; // ID for socket for UDP traffic
bool running; // Indicates server is on
bool TCPMODE; // True for TCP, false for UDP
bool OVRMODE; // Whether to override clients request for individual modes
bool TCPMODE_SET; // Contains TCPMODE if OVRMODE set, otherwise contains clients.TCPMODE
ifstream waveFile("radio.wav",ios::in|ios::binary|ios::ate); //
//ofstream tempFile("verify.wav",ios::out|ios::binary|ios::ate);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNTION PROTOTYPES
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWave ( void ); // Loads wavefile and fills out the struct with header data + prepares buffer
void updateProgramInfo ( void ); // Adds timestamp + info to struct for wavefile
void initServer ( void ); // Starts server
bool checkForNewClients ( void ); // Checks for new listener
void disconnectClient ( int ); // Removes a listener
void sendProgramInfo ( int ); // Sends info about the program to the new listener
void getMessage ( int ); // Receive message from clients
void broadcastAudio ( void ); // Sends next part of the radioprogram to the listener

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// LOAD WAVE FILE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWave( void ){
broadCast.headerSize = HEADERSIZE;
broadCast.byteSize = waveFile.tellg() - broadCast.headerSize;
waveFile.seekg(0, ios::beg);
broadCast.headerData = new char[broadCast.headerSize];
for(j=0; j {
broadCast.headerData[j] = 0;
}
waveFile.read(broadCast.headerData, broadCast.headerSize);
printf("Buffering %d bytes of headerdata\n",broadCast.headerSize);
//tempFile.write(broadCast.headerData, broadCast.headerSize); // Used for local verification purposes
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// STORE TIMESTAMP + PROGRAM INFO
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void updateProgramInfo( void ){
SYSTEMTIME timer;
char temp[1024]; // used for misc stringmanipulation
char timeClk[25];
char date[25];
char *timeStamp; // puts timedata in string
// Store broadcast-start timestamp in broadCast.programInfo and log-file
strcpy(temp, "Station up at ");
GetLocalTime(&timer); // gets local time from system
GetDateFormat(0,DATE_SHORTDATE,&timer,NULL,date,sizeof(date));
GetTimeFormat(0,LOCALE_NOUSEROVERRIDE,&timer,NULL,timeClk,sizeof(timeClk));
timeStamp = date; strcat( timeStamp, " at "); strcat( timeStamp, timeClk);
strcat(temp, timeStamp); strcat(temp,"\n");
logFile = fopen("radiolog.log", "a"); //Open or create file for both reading and appending
fprintf(logFile,temp); // stores string as a line in the log-file
broadCast.programInfo = new char[SENDBUFFERSIZE];
for(j=0; j {
broadCast.programInfo[j] = 0;
}
strcpy( broadCast.programInfo, temp ); // Appends timestamp to broadCast.programInfo
printf("%s",broadCast.programInfo);
broadCast.done = false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// START SERVER FOR BROADCASTING
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void initServer( void ){
// Create a socket for requests
if ((TCPSocket = socket(DOMAIN_AF, SOCK_STREAM, PROTOCOL)) < 0){
printf("*** System unable to create TCP listeningsocket ***\n");
exit(1);
}
if ((UDPSocket = socket(DOMAIN_AF, SOCK_DGRAM, PROTOCOL)) < 0){
printf("*** System unable to create UDP listeningsocket ***\n");
exit(1);
}

// Fill in addressinfo for local socket
localHostName = new char[80];
for(j=0; j<80; j++)
{
localHostName[j] = 0;
}
gethostname( localHostName, sizeof(localHostName) );
localInfo = gethostbyname(localHostName);
if (localInfo == NULL){
printf("*** Could not get IP ***\n");
exit(1);
} else memcpy(&localIP, localInfo->h_addr, 4);
localAddress.sin_family = DOMAIN_AF;
localAddress.sin_port = htons(servePort); // convert 16-bit values between host and network byte order
localAddress.sin_addr.s_addr = INADDR_ANY;

// Bind socket to address
if( bind( TCPSocket, (struct sockaddr *)&localAddress, sizeof(localAddress) ) <0 ){
printf("*** System unable to bind TCP socket ***\n");
exit(1);
}
if( bind( UDPSocket, (struct sockaddr *)&localAddress, sizeof(localAddress) ) <0 ){
printf("*** System unable to bind UDP socket ***\n");
exit(1);
}
printf("Radio %s on %s:%d\n\n",localHostName, inet_ntoa(localIP), servePort);
listen( TCPSocket, MAXQUEUE ); // Listen for connectionrequests
for (int i=0; i }//END INITSERVER

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHECK FOR NEW LISTENERS REQUESTING TO LISTEN TO THE RADIO
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Returns true if connection is made, false if no connections attempted or no free radioslots
bool checkForNewClients( void ){
int selectResult; // data returned from the select function
int nfds; // New filedescriptor to allow multiple connectionrequests
fd_set conn; // read variable for select function

timeout.tv_sec = 0; // set to 0 for Non Blocking
timeout.tv_usec = 0;

if (numberOfClients < MAXCLIENTS)
{
FD_ZERO (&conn);
FD_SET (TCPSocket, &conn); // conn get the data from the listeningsocket
nfds = TCPSocket + 1; // Up by one - shouldnt be the same for each client connecting

selectResult = select(nfds, &conn, NULL, NULL, &timeout); // Check if any data is coming in...

if (selectResult > 0) // Someone is trying to Connect
{
int i = 0;
char *clientMode;
char temp[1024];

while(clients[i].connected == true && i < MAXCLIENTS){
i++;
}
if (clients[i].connected == true) return false; // All slots full

clients[i].addressLength = sizeof(clients[i].address);
clients[i].socket_fd = accept(TCPSocket,
(struct sockaddr *)&clients[i].address,
&clients[i].addressLength);
// Client Connected
numberOfClients++;
clients[i].connected = true;
memcpy( &clients[i].IP, &clients[i].address.sin_addr.s_addr, 4 ); // Gets IP for client
clients[i].nickName = new char[31];
for(j=0; j<31; j++)
{
clients[i].nickName[j] = 0;
}
clientMode = new char[2]; //receivebuffer = expected databytes +1 for stringterminator
clientMode[0] = clientMode[1] = 0;
recv( clients[i].socket_fd, clients[i].nickName, 30, 0 );
recv( clients[i].socket_fd, clientMode, 1, 0 );
if (clientMode[0] == ''1'') clients[i].TCPMODE = true; else clients[i].TCPMODE = false;
strcpy( temp, clients[i].nickName);
strcat( temp, "(");
strcat( temp, inet_ntoa(clients[i].IP));
strcat( temp, ")");
memset ( clients[i].nickName, ''\0'', sizeof(clients[i].nickName) ); // Clears out inbuffer before use
strcpy(clients[i].nickName,temp);
printf("\n* * * %s tuned in at slot %d requesting ",clients[i].nickName,i);
if (clients[i].TCPMODE == true) printf("TCPMODE\n"); else printf("UDPMODE\n");
fprintf(logFile,"Tuned in ");
fprintf(logFile,clients[i].nickName); // stores string as a line in the log-file
fprintf(logFile,"\n");

sendProgramInfo(i);

char inBuffer[20];
char outBuffer[20];
strcpy(outBuffer,"OK");
memset ( inBuffer, ''\0'', sizeof(inBuffer) ); //clears out inbuffer before use
recvfrom( UDPSocket, inBuffer, 19, 0,
(struct sockaddr *)&clients[i].address, &clients[i].addressLength);
sendto(UDPSocket, outBuffer, 19, 0,
(struct sockaddr *)&clients[i].address, clients[i].addressLength);
} else return false; // No connection attempts at this time
}
return true; // Connected a new client
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SEND PROGRAM INFO TO NEW LISTENER
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void sendProgramInfo(int i){
send(clients[i].socket_fd, broadCast.programInfo, SENDBUFFERSIZE, 0 );
send(clients[i].socket_fd, broadCast.headerData, HEADERSIZE, 0 );
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SEND THE AUDIOSTREAM TO ALL LISTENERS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void broadcastAudio( void ){
int prevNoListeners = 0;
int bytesToSend = SENDBUFFERSIZE;
int chunkNo = 0;
char *sendBuffer;

// Send chunks
broadCast.bytesLeft = broadCast.byteSize;
broadCast.bytesSent = 0;

while(broadCast.done == false){
// wait for a couple of MS so the receiver can process in the speed being sent...
Sleep(10);
chunkNo++; // Keep count of how many chunks are being sent
// Prepare sendbuffer and how many bytes to send
if (broadCast.bytesLeft < SENDBUFFERSIZE){
bytesToSend = broadCast.bytesLeft;
broadCast.done = true;
}
broadCast.bytesLeft -= bytesToSend;
broadCast.bytesSent += bytesToSend;
sendBuffer = new char[bytesToSend];
for(j=0; j waveFile.read(sendBuffer, bytesToSend); // Put next chunk of audiostream into sendBuffer
//tempFile.write(sendBuffer, bytesToSend); // Used for local verification

// If more listeners have tuned in, print a little message to screen
if (prevNoListeners != numberOfClients) printf("Sending to %d listener(s): ",numberOfClients);
prevNoListeners = numberOfClients;
for (int i=0; i if (clients[i].connected){
if (OVRMODE) TCPMODE_SET = TCPMODE; else TCPMODE_SET = clients[i].TCPMODE;
if (TCPMODE_SET) send(clients[i].socket_fd, sendBuffer, bytesToSend,0);
else sendto(UDPSocket, sendBuffer, bytesToSend, 0,
(struct sockaddr *)&clients[i].address, clients[i].addressLength);
//if (TCPMODE_SET) printf("t"); else printf("u");
}
}
if (broadCast.bytesSent == broadCast.byteSize) broadCast.done = true;
else checkForNewClients();
}
printf("\n%d chunks DONE\n",chunkNo);
waveFile.close();
//tempFile.close();
printf("\nSending EOP to slot(s): ");
for (int i=0; i char *terminate;
terminate = new char[4];
strcpy(terminate,"EOP");
terminate[4] = 0;
if (clients[i].connected){
printf("%d.",i);
if (OVRMODE) TCPMODE_SET = TCPMODE; else TCPMODE_SET = clients[i].TCPMODE;
if (TCPMODE_SET) send(clients[i].socket_fd, terminate, bytesToSend, 0 );
else {printf(".");
sendto(UDPSocket, terminate, bytesToSend, 0,
(struct sockaddr *)&clients[i].address, clients[i].addressLength);
}
}
}
printf("\n");
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHECK FOR INCOMING CLIENT-MESSAGES
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void checkForMessages()
{
fd_set input_set,
exc_set; // Input and Error sets for the select function
int selectResult, // This is Used for the Select command to store the value it gets back
nfds; // New filedescriptor to allow multiple connectionrequests
timeout.tv_sec = 0; // 0 for non-blocking
timeout.tv_usec = 0;
nfds = 0;
FD_ZERO(&input_set); // Set up the input,and exception sets for select().
FD_ZERO(&exc_set);

for (int i = 0; i < MAXCLIENTS // Add all connected sockets to set for checking
{
if (clients[i].connected == true){
FD_SET(clients[i].socket_fd,&input_set);
FD_SET(clients[i].socket_fd,&exc_set);
}
nfds++;
i++;
}
selectResult = select(nfds,&input_set,NULL,&exc_set,&timeout); // Checks for incoming
if (selectResult > 0)
{
for (int i=0; i < numberOfClients //Look through all the clients to see which one is giving error or data
{
if (FD_ISSET(clients[i].socket_fd,&exc_set)) // Error on socket
{
// Assume error means disconnection
printf("*%s disconnected from slot %d\n",clients[i].nickName,i);
disconnectClient(i);
}

if ((FD_ISSET(clients[i].socket_fd, &input_set))) // Incoming message
{
// Get whatever message the client sending, and carry out appropriate response
getMessage(i);
}
i++; // Next Client
}
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PROCESS CLIENT-MESSAGES
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// (not used in this program, but included for later versions, if any)
// Get the message, and see what it is.
void getMessage(int i){
// Receive The Data and Put into a Buffer Until we know what it is.
char *rcvBuffer;
rcvBuffer = new char[2]; //receivebuffer = expected databytes +1 for stringterminator
rcvBuffer[0] = rcvBuffer[1] = 0;
if (OVRMODE) TCPMODE_SET = TCPMODE; else TCPMODE_SET = clients[i].TCPMODE;
if (TCPMODE_SET) recv(clients[i].socket_fd,rcvBuffer,1,0);
else recvfrom( UDPSocket, rcvBuffer, 1, 0, (struct sockaddr *)&clients[i].address, &clients[i].addressLength);
switch (rcvBuffer[0])
{
case ''1'':
printf("*%s requested TCPMODE on slot %d\n",clients[i].nickName,i);
clients[i].TCPMODE = true;
break;
case ''2'':
printf("*%s requested UDPMODE on slot %d\n",clients[i].nickName,i);
clients[i].TCPMODE = false;
break;
case ''3'':
printf("*%s stopped listening on slot %d\n",clients[i].nickName,i);
disconnectClient(i);
break;
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DISCONNECT A LISTENER
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void disconnectClient(int i){
closesocket(clients[i].socket_fd);
clients[i].connected = false;
numberOfClients--;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SHUTDOWN THE ENTIRE SERVER
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void shutdownServer( void ){
closesocket(TCPSocket);
closesocket(UDPSocket);
for (int i = 0; i < MAXCLIENTS, i++
{
if (clients[i].connected) disconnectClient(i);
}
WSACleanup(); // Remove Winsock
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MAIN
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]){
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);
char *choice;
running = true;
numberOfClients = 0;
printf("\n<<< Winsock TCP/UDP Radio Broadcaster >>>\n (C) 2002 Trond Borg\n\n");
choice = new char[1];
printf("Select 1 : CLIENT SELECT MODE\n");
printf(" 2 : TCP ONLY MODE\n");
printf(" 3 : TCP ONLY MODE : ");
scanf ("%s", choice); // read userid from keyboard into userID
if(!strcmp(choice,"1")){
OVRMODE = false;
}
if(!strcmp(choice,"2")){
TCPMODE = true;
OVRMODE = true;
}
if(!strcmp(choice,"3")){
TCPMODE = false;
OVRMODE = true;
}
if(OVRMODE){
if(TCPMODE) printf("TCP ONLY MODE Enabled\n"); else printf("UDP ONLY MODE Enabled\n");
}else printf(" CLIENT SELECT MODE Enabled\n");

printf("\n");
loadWave();
updateProgramInfo();
if (argc < 2){
servePort = 888;
}
else servePort = atoi(argv[1]);
initServer();
//printf("Splitting wavedata into %d bit chunks for broadcasting\n",SENDBUFFERSIZE);
printf("Waiting for a listener before starting program\n");
while (numberOfClients == 0){
// wait a little or CPU-usage goes up to a 100%
// FIX
Sleep(1000);
checkForNewClients(); // Dont start radio until at least one listener is ready
}
broadcastAudio(); // Send the audiofile chunk by chunk
shutdownServer(); // For all clients, close socket:
printf("Server closed down\n");
scanf ("%s",choice);
return(0);
}//END MAIN


"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
I think I''ve found your error.

It appears that you are doing things slightly out-of-order.


  
void getAudio( void )
{
char *soundData; // 128 with zero fill, msgformat from server

int audioBytesRead,
totalBytesRead,
chunksRead;

listening = true;
soundData = new char[READBUFFERSIZE];

printf("Receiving broadcast sound-data\n");
while (listening == true)
{
audioBytesRead = recv(local_socket_fd, soundData, READBUFFERSIZE, 0);

totalBytesRead += audioBytesRead;
if (audioBytesRead > 0)
{
chunksRead++;
// printf(".");


if(soundData[0] == ''E'')
{
// Server sends message containing "EOP" when radio-program is finished

// HUGE ASSUMPTION HERE.

if(soundData[1] == ''O'')
{
if( soundData[2] == ''P'')
{
printf("\n%s - Shutting Down\n",soundData);

listening = false;
}
}
}
else
{
// Append wave-data to file

// changed READBUFFERSIZE to audioBytesRead

// you were potentially writing corrupt data.

audioCache.write(soundData, audioBytesRead);
}

// Play sounddata after caching enough data


}
}
}


See if that works. Other than that I''d have to spend more time with you code and unfortunately it isn''t that pretty to read Good luck.

Share this post


Link to post
Share on other sites
BTW You are also making a huge assumption that the TCP/IP packets will arrive in discreet sizes.

Say the server sends:


send("12345678")


and then:


send("EOP")


But on the client you recv:

"12345678EOP"

Your code above doesn't know how to handle this. You should change your server code to send a packet length header. Like:


dataHeader.messageType = DATA_MESSAGE;
dataHeader.messageLength = bytesToSend;

while(broadcast.done == false)
{
// more code
// ignoring byte ordering and packing
// send header
send(client,
(char*)&dataHeader,
sizeof(dataHeader.messageLength),
0);

// send data
send(client, data, bytesToSend, 0);

// more code
}


The server then sends an EOP_MESSAGE type when the end of the program has been reached:


dataHeader.messageType = EOP_MESSAGE;
dataHeader.messageLength = 0;


This would allow your client to figure out how many bytes it needs to receive. This would also allow you to recognize when you receive an EOP.

If you need help with implementing this, let me know.

Regards.

[edited by - Digitalfiend on December 10, 2002 8:36:38 PM]

Share this post


Link to post
Share on other sites
kool, I will try that out. Allthough I dont understand what I am doing out-of-order? The reason I put the
<> inside the loop was to clear it out between each send?

Can you explain why I dont need that? I am terrible with strings...



"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
sorry... I meant :
soundData = new char[READBUFFERSIZE+1];
within the while loop

"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites
I think Digitalfiend deserves a pat on the back for being so helpful in this (and other) threads: pat pat...

trondb: if you are not so interested in learning the workings of sockets and just want to get the data across successfully you could use my sockets wrapper, it is easy to use and fully documented on my website, there is an example to show how to do a simple file transfer:
http://www.zppz.com/libraries/minisock/index.jsp
(runs on windows and linux)

Share this post


Link to post
Share on other sites
Thanks zppz

BTW trondb, I made a litle bit of a goof in my pseudo-code above.

change:


send(client,
(char*)&dataHeader,
sizeof(dataHeader.messageLength) ,
0);


to


send(client,
(char*)&dataHeader,
sizeof(dataHeader) ,
0);


BTW Let me know if you are still having problems. I''ll whip up a small example for you when I get a chance.

Good luck.

Share this post


Link to post
Share on other sites
Again, thanks alot Digitalfiend! It rocks to have people like you out there to help out when my skills don''t cut it!!! I am currently cramp-studying for my final exams, so I will have to implement this a little later in the week, but I''m sure its gonna work now!!! Thanks again (Y)

"That''s Tron. He fights for the users."

Share this post


Link to post
Share on other sites

  • Advertisement