Music\Sounds over Network (SDL_Net)

Started by
16 comments, last by hplus0603 11 years, 11 months ago
Alright, my library of choice is SDL_Net, documentation isn't that great, but I bet it's pretty simple once I learn how transfer things between the client. I've got a simple console application using the little tutorial on the SDL_Net Wiki. What it does is create a TCP connection between the client and server and the client can send messages to the server, and the server prints them out on the server console. The tutorial came with two commands that it does a strcmp with this char buffer[512] which are exit and quit. Obvious as they are, "exit" closes the client; "quit" closes both the server and the client.

So I added in my own commands and allowed the server to play music\sounds, but what good is that if I'm away from the server? I also followed another guide to get the IP to appear in the x.x.x.x format as opposed to the hex format which was made for winsock, but still works all the same.

Anyway, we come to the problem that I'm trying to figure out is how can I play music\sounds from the server and play them on the client? (Streaming) I assume I need a buffer or some sort to send a little bit at a time, and free the memory once it's done, but to be perfectly honest, I have no idea how.

Anyhow, here's my current server code (Since I'm new to this, I left the comments from the SDL_Net Wiki page there):



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL.h>
#include <SDL_mixer.h>
#include <SDL_net.h>
Mix_Music* alien = NULL;
TCPsocket sd, csd; /* Socket descriptor, Client socket descriptor */
IPaddress ip, *remoteIP;
void Clean()
{
SDLNet_TCP_Close(sd);
SDLNet_Quit();
if (Mix_PlayingMusic() == 1)
Mix_HaltMusic();
Mix_FreeMusic(alien);
Mix_CloseAudio();
}
int main(int argc, char **argv)
{
if( Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096) < 0)
{
FILE* lerr = fopen("errlog.txt", "wb+");
fprintf(lerr, "Error opening audio.\n");
fclose(lerr);
exit(EXIT_FAILURE);
}
atexit(Clean);
alien = Mix_LoadMUS("alien.mp3");
if (!alien)
{
FILE* lerr = fopen("errlog.txt", "wb+");
fprintf(lerr, "Error opening alien.mp3.\n");
fclose(lerr);
exit(EXIT_FAILURE);
}
int quit, quit2;
char buffer[512];
if (SDLNet_Init() < 0)
{
FILE* lerr = fopen("errlog.txt", "wb+");
fprintf(lerr, "SDLNet_Init: %s\n", SDLNet_GetError());
fclose(lerr);
exit(EXIT_FAILURE);
}
/* Resolving the host using NULL make network interface to listen */
if (SDLNet_ResolveHost(&ip, NULL, 2000) < 0)
{
FILE* lerr = fopen("errlog.txt", "wb+");
fprintf(lerr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
fclose(lerr);
exit(EXIT_FAILURE);
}
/* Open a connection with the IP provided (listen on the host's port) */
if (!(sd = SDLNet_TCP_Open(&ip)))
{
FILE* lerr = fopen("errlog.txt", "wb+");
fprintf(lerr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
fclose(lerr);
exit(EXIT_FAILURE);
}
/* Wait for a connection, send data and term */
quit = 0;
while (!quit)
{
/* This check the sd if there is a pending connection.
* If there is one, accept that, and open a new socket for communicating */
if ((csd = SDLNet_TCP_Accept(sd)))
{
/* Now we can communicate with the client using csd socket
* sd will remain opened waiting other connections */
/* Get the remote address */
if ((remoteIP = SDLNet_TCP_GetPeerAddress(csd)))
{
/* Print the address, converting in the host format */
unsigned char IP[4] = {0,0,0,0};
for (int i=0; i<4; i++)
{
IP = ( SDLNet_Read32(&remoteIP->host) >> (i*8) ) & 0xFF;
}
printf("Client connected: %d.%d.%d.%d:%d\n", IP[3],IP[2],IP[1],IP[0], SDLNet_Read16(&remoteIP->port));
}
else
{
FILE* lerr = fopen("errlog.txt", "wb+");
fprintf(lerr, "SDLNet_TCP_GetPeerAddress: %s\n", SDLNet_GetError());
fclose(lerr);
}
quit2 = 0;
while (!quit2)
{
if (SDLNet_TCP_Recv(csd, buffer, 512) > 0)
{
printf("Client said: %s\n", buffer);
if(strcmp(buffer, "exit") == 0) /* Terminate this connection */
{
quit2 = 1;
printf("Client terminated the connection...\n");
}
if(strcmp(buffer, "quit") == 0) /* Quit the program */
{
quit2 = 1;
quit = 1;
printf("Client terminated server...\n");
}
if (strcmp(buffer, "alien") == 0)
{
if (Mix_PlayingMusic() == 0)
Mix_PlayMusic(alien, -1);
}
if (strcmp(buffer, "stop") == 0)
{
if (Mix_PlayingMusic() == 1)
Mix_HaltMusic();
}
if (strcmp(buffer, "pause") == 0)
{
if (Mix_PlayingMusic() == 1)
Mix_PauseMusic();
}
if (strcmp(buffer, "resume") == 0)
{
if (Mix_PausedMusic() == 1)
Mix_ResumeMusic();
}
}
}
/* Close the client socket */
SDLNet_TCP_Close(csd);
}
}
return EXIT_SUCCESS;
}


And here is my client code:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL_net.h>
int main(int argc, char **argv)
{
IPaddress ip; /* Server address */
TCPsocket sd; /* Socket descriptor */
int quit, len;
char buffer[512];
/* Simple parameter checking */
if (argc < 3)
{
FILE* lerr = fopen("lerr.txt", "w+");
fprintf(lerr, "Usage: %s host port\n", argv[0]);
fclose(lerr);
exit(EXIT_FAILURE);
}
if (SDLNet_Init() < 0)
{
FILE* lerr = fopen("lerr.txt", "w+");
fprintf(lerr, "SDLNet_Init: %s\n", SDLNet_GetError());
fclose(lerr);
exit(EXIT_FAILURE);
}
/* Resolve the host we are connecting to */
if (SDLNet_ResolveHost(&ip, argv[1], atoi(argv[2])) < 0)
{
FILE* lerr = fopen("lerr.txt", "w+");
fprintf(lerr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
fclose(lerr);
exit(EXIT_FAILURE);
}
/* Open a connection with the IP provided (listen on the host's port) */
if (!(sd = SDLNet_TCP_Open(&ip)))
{
FILE* lerr = fopen("lerr.txt", "w+");
fprintf(lerr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
fclose(lerr);
exit(EXIT_FAILURE);
}
/* Send messages */
quit = 0;
while (!quit)
{
printf(">");
scanf("%s", buffer);
len = strlen(buffer) + 1;
if (SDLNet_TCP_Send(sd, (void *)buffer, len) < len)
{
FILE* lerr = fopen("lerr.txt", "w+");
fprintf(lerr, "SDLNet_TCP_Send: %s\n", SDLNet_GetError());
fclose(lerr);
exit(EXIT_FAILURE);
}
if(strcmp(buffer, "exit") == 0)
quit = 1;
if(strcmp(buffer, "quit") == 0)
quit = 1;
}
SDLNet_TCP_Close(sd);
SDLNet_Quit();
return EXIT_SUCCESS;
}

Any help is appreciated
Advertisement
Is there a particular reason you want to stream the sound to the client? Typically you would just send a command from the server to the client that says "play sound #3845" or whatever, and the client uses a local sound resource to actually fulfill the command.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


Is there a particular reason you want to stream the sound to the client? Typically you would just send a command from the server to the client that says "play sound #3845" or whatever, and the client uses a local sound resource to actually fulfill the command.

Well, I understand that, that's simple to do, but I want to understand for one, how streaming works, and two, how to copy files over a network. If I can do those and I understand how, I feel pretty much golden. Except the fact that I made local file pointers in the server and opened them with "wb+" if there was an error, aye, what a lamebrain mistake.
Alright after working at something related to printing to the client's console, I realized something. It can't be done with SDLNet_TCP_Send, as it's a client only function, at least according to the documentation.
SDLNet_TCP_Send sends the data over the socket. If the data cannot be sent immediately, the routine waits until all of the data may be delivered properly (it is a blocking operation). This routine is not used for server sockets.[/quote]

The only possible way I see that I can send messages to the client through a buffer, or any data to the client, I would need some sort of double connection using multiple sockets. I tried that already, but I couldn't get it to work. Unless there's another function I'm missing.
Answer this question: "How do I play music from a FILE on the client, when all I have is the file handle (not the path)?"
Once you have that answer, you should be very close to the answer for "how do I play music from a socket handle?"
enum Bool { True, False, FileNotFound };

Answer this question: "How do I play music from a FILE on the client, when all I have is the file handle (not the path)?"
Once you have that answer, you should be very close to the answer for "how do I play music from a socket handle?"

Well, the way I see it is that I can have multiple Mix_Music pointers and I can do something like mus1 = Mix_LoadMUS("mus.mp3"); then have mus2 = mus1, and so on. I'm not 100% sure on that, as pointers are just now becoming a nightmare. The simple answer would be to read something into "musClient" (assuming we have the Mix_Music* musClient) that is sent over from the server that has "musServer" and loads it so the client just has to play it. A file transfer could likely be achieved the same way. The main problem with this is right now is that apparently the server in SDL_Net can't send data to the client, and can only receive data from it. The second problem is that I need the length in bytes of the Mix_Music pointer that would be sent, which as I understand would only return 4 with any given pointer.

Aye, I'm only 16 maybe I should just give up until I have an actual teacher.
Mix_LoadMUS("mus.mp3");[/quote]

That's a filename, not a file pointer.

It *may* be that the library you are using doesn't actually support playing from a socket handle. If so, see if it supports playing from raw memory, and if so, download the file to memory and play from there.


Aye, I'm only 16 maybe I should just give up until I have an actual teacher. [/quote]

Age is just a number! Don't give up when it gets hard. Instead, I find I make progress if I can step back and figure out *why* something is hard, and then figure out how to remove that underlying problem. Books, tutorials, tutors, forums, reading other people's code, and sleeping on the problem are all important parts of learning, and no one solution will always be right.
To become a programmer, you need a really high tolerance level for frustration, though :-)
enum Bool { True, False, FileNotFound };

Mix_LoadMUS("mus.mp3");


That's a filename, not a file pointer.

It *may* be that the library you are using doesn't actually support playing from a socket handle. If so, see if it supports playing from raw memory, and if so, download the file to memory and play from there.


Aye, I'm only 16 maybe I should just give up until I have an actual teacher. [/quote]

Age is just a number! Don't give up when it gets hard. Instead, I find I make progress if I can step back and figure out *why* something is hard, and then figure out how to remove that underlying problem. Books, tutorials, tutors, forums, reading other people's code, and sleeping on the problem are all important parts of learning, and no one solution will always be right.
To become a programmer, you need a really high tolerance level for frustration, though :-)
[/quote]

Thanks. The file pointer I talking about is when you create a Mix_Music*. This can be found under the SDL_Mixer library. There's a reason I made a thread before this asking about which libraries to use for networking and SDL_Net was appealing for it's portability and its ability to be able to use plain C or C++.

Either way, I'm not trying to recreate the same topic. I've been thinking a bit backwards here, I'm trying to figure out how to send music from a server to a client without first trying to figure out how to so much as send information to the client. The server can receive information fine, and the client can send information fine, but not the other way around. The server cannot send information, and the client can't receive information. I tried the simple creating a second char to send to the client. It would actually be more appropriate to send an int for this particular situation. Either way I tried sending a char to the client containing something like '0' or '1' and then have the client print out a message corresponding to the number it got.

This is impossible as I said before, the SDLNet_TCP_Send() is designed for the client only (according to the documentation). So then, how can I possibly send data to the client? The odd part is I'm using TCP, and looking at the documentation, there doesn't appear to be such a limitation to UDP.
the SDLNet_TCP_Send() is designed for the client only (according to the documentation).[/quote]

It is?

Perhaps this is confusing:
... such as the client disconnecting.[/quote]
I prefer the term "peer" for this purpose, since it doesn't confuse terminology or imply direction.

But no, client here means "the thing on the other side of TCP connection", nothing more.

The server cannot send information, and the client can't receive information.[/quote]

If you can send in one direction, you can send in other. But hard to say without more detail.

Have you tried first going through the SDLNet tutorial?

the SDLNet_TCP_Send() is designed for the client only (according to the documentation).


It is?
[/quote]
Under the description read this SDLNet_TCP_Send sends the data over the socket. If the data cannot be sent immediately, the routine waits until all of the data may be delivered properly (it is a blocking operation). This routine is not used for server sockets."


The server cannot send information, and the client can't receive information.


If you can send in one direction, you can send in other. But hard to say without more detail.

Have you tried first going through the SDLNet tutorial?
[/quote]
Everything I have is from the SDL_Net tutorial and messing with the code.


Anyhow, here's my current server code (Since I'm new to this, I left the comments from the SDL_Net Wiki page there):


After all that is kind of why I'm here, because there's that one tutorial, and barely any others if any. (As in no others that I could find)

This topic is closed to new replies.

Advertisement