seek help
蒋鹏
jpplus at 163.com
Sun Jan 19 23:23:00 EST 2003
Hi:
I am a uviertity student wants make a network mp3 player with sdl-sound.
I start a thread of rtp to reciever rtp packet from network interface,and start a thread to decode(mp3) and playback the audio.I add the rtp-packet to a queue and decode it to a big buffer.Now the audio can be played but play 3 second then stop ,I think the
callback function of sdl audio confuse me.
Need I start a new thread to prepare the big size buffer ,and is the callback function return after play all the data in the big size buffer.
here is my program:
#include "lame.h"
#include <sys/timeb.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "memory.h"
#include "rtp.h"
#include "SDL.h"
#include "SDL_audio.h"
#include "SDL_thread.h"
#define MAXSIZE 44100*5
#ifdef WIN32
#define WS_VERSION_ONE MAKEWORD(1,1)
#define WS_VERSION_TWO MAKEWORD(2,2)
#endif
#define MAXPCM 44100*5
typedef struct pcm_data
{
uint8_t * data;
uint32_t data_len;
struct pcm_data * next;
} PCM_DATA_T;
/******************global variable**********************/
PCM_DATA_T header={NULL,0,NULL};
PCM_DATA_T *current;
struct rtp * session;
SDL_mutex *mutex = NULL;
static SDL_sem *sem;
uint8_t *sound; /* Pointer to wave data */
uint32_t soundlen; /* Length of wave data */
int soundpos; /* Current play position */
uint8_t pcmBuffer[MAXPCM];
/******************************************************/
static void
usage()
{
printf("Usage: rtpdemo [switches] address port\n");
printf("Valid switches are:\n");
printf(" -f\t\tFilter local packets out of receive stream.");
printf(" -l\t\tListen and do not transmit data.\n");
exit(-1);
}
/* ------------------------------------------------------------------------- */
/* RTP callback related */
static void
sdes_print(struct rtp *session, uint32_t ssrc, rtcp_sdes_type stype) {
const char *sdes_type_names[] = {
"end", "cname", "name", "email", "telephone",
"location", "tool", "note", "priv"
};
const uint8_t n = sizeof(sdes_type_names) / sizeof(sdes_type_names[0]);
if (stype > n) {
/* Theoretically impossible */
printf("boo! invalud sdes field %d\n", stype);
return;
}
printf("SSRC 0x%08x reported SDES type %s - ", ssrc,
sdes_type_names[stype]);
if (stype == RTCP_SDES_PRIV) {
/* Requires extra-handling, not important for example */
printf("don't know how to display.\n");
} else {
printf("%s\n", rtp_get_sdes(session, ssrc, stype));
}
}
static void
addtoQueue(struct rtp *session, rtp_packet *p)
{
static uint32_t counter=0;
uint16_t pcmBuffer[2][1152];
PCM_DATA_T *temp=&header;
PCM_DATA_T * tempPacket=(PCM_DATA_T *)malloc(sizeof(PCM_DATA_T));/*when use the data,remeber to free the queue packet and xfree the rtp*/
if(tempPacket==NULL)
{
printf("no enough memory left");
exit(-1);
}
printf("Received data (payload=%d timestamp=%06d size=%06d) ", p->rtp_pak_pt, p->rtp_pak_ts, p->rtp_data_len);
/*begin decode*/
/*end decode*/
SDL_mutexP(mutex);
tempPacket->data=(uint8_t *)malloc(p->rtp_data_len);
tempPacket->next =NULL;
memcpy(tempPacket->data,p->rtp_data,p->rtp_data_len);
tempPacket->data_len=p->rtp_data_len;
tempPacket->next=NULL;
while(temp->next!=NULL)//find the last
{temp=temp->next;
}
temp->next=tempPacket;
SDL_mutexV(mutex);
SDL_SemPost(sem);
printf("I get %d packet\n",counter++);
printf("the current value is %d \n",SDL_SemValue(sem));
if (p->rtp_pak_ssrc == rtp_my_ssrc(session)) {
/* Unless filtering is enabled we are likely to see
out packets if sending to a multicast group. */
printf("that I just sent.\n");
} else {
printf("from SSRC 0x%08x\n", p->rtp_pak_ssrc);
}
}
static void
rtp_event_handler(struct rtp *session, rtp_event *e)
{
rtp_packet *p;
rtcp_sdes_item *r;
switch(e->type) {
case RX_RTP:
p = (rtp_packet*)e->data;
addtoQueue(session, p);
xfree(p); /* xfree() is mandatory to release RTP packet data */
break;
case RX_SDES:
r = (rtcp_sdes_item*)e->data;
sdes_print(session, e->ssrc, r->type);
break;
case RX_BYE:
break;
case SOURCE_CREATED:
printf("New source created, SSRC = 0x%08x\n", e->ssrc);
break;
case SOURCE_DELETED:
printf("Source deleted, SSRC = 0x%08x\n", e->ssrc);
break;
case RX_SR:
case RX_RR:
case RX_RR_EMPTY:
case RX_RTCP_START:
case RX_RTCP_FINISH:
case RR_TIMEOUT:
case RX_APP:
; }
fflush(stdout);
}
/* ------------------------------------------------------------------------- */
/* Send and receive loop. Sender use 20ms audio mulaw packets */
#define MULAW_BYTES 4 * 160
#define MULAW_PAYLOAD 0
#define MULAW_MS 4 * 20
static void
recieve_packet(struct rtp* session, int send_enable)
{
struct timeval timeout;
uint32_t rtp_ts;
if (send_enable) {
printf("Sending and listening to ");
} else {
printf("Listening to ");
}
printf("%s port %d (local SSRC = 0x%08x)\n",
rtp_get_addr(session),
rtp_get_rx_port(session),
rtp_my_ssrc(session));
while(1){
/* Receive control and data packets */
timeout.tv_sec = 0;
timeout.tv_usec = 5;
rtp_recv(session, &timeout, rtp_ts);
/* State maintenance */
rtp_update(session);
file://sleep(1);
xmemchk();
}
}
static int recieverCallback(void *data)
{
struct timeval timeout;
int retcode;
#ifdef WIN32
WSADATA WSAdata;
if (WSAStartup(WS_VERSION_TWO, &WSAdata) != 0 && WSAStartup(WS_VERSION_ONE, &WSAdata) != 0) {
printf("Windows Socket initialization failed.\n");
return 1;
}
debug_msg("WSAStartup OK: %sz\nStatus:%s\n", WSAdata.szDescription, WSAdata.szSystemStatus);
#endif
// memcpy(address,&data[sizeof(uint16_t)],sizeof(uint16_t));
printf("Started thread %s: My thread id is %u\n",(char *)data, SDL_ThreadID());
session = rtp_init((char *)data, /* Host/Group IP address */
8000, /* receive port */
8000, /* transmit port */
16, /* time-to-live */
64000, /* B/W estimate */
rtp_event_handler, /* RTP event callback */
NULL); /* App. specific data */
if (session) {
const char *username = "Malcovich Malcovitch";
const char *telephone = "1-800-RTP-DEMO";
const char *toolname = "RTPdemo";
uint32_t my_ssrc = rtp_my_ssrc(session);
/* Set local participant info */
rtp_set_sdes(session, my_ssrc, RTCP_SDES_NAME,
username, strlen(username));
rtp_set_sdes(session, my_ssrc, RTCP_SDES_PHONE,
telephone, strlen(telephone));
rtp_set_sdes(session, my_ssrc, RTCP_SDES_TOOL,
toolname, strlen(toolname));
/* Filter out local packets if requested */
rtp_set_option(session, RTP_OPT_FILTER_MY_PACKETS, 0);
/* Run main loop */
recieve_packet(session, 0);
/* Say bye-bye */
rtp_send_bye(session);
rtp_done(session);
} else {
printf("Could not initialize session for %s port %d\n",
(char *)data,
8000);
return -1;
}
#ifdef WIN32
Sleep(2000);
WSACleanup();
#endif
return(0);
}
/**/
static void prepareBuffer()
{
uint32_t index=0;
PCM_DATA_T * temp=&header;
uint16_t Buffer[2][1152];
mp3data_struct mp3data;
int counter=0;
#define MP3SIZE 1024*2
uint8_t mp3buf[MP3SIZE];
uint32_t ret=0;
mp3data.samplerate=22050;
mp3data.stereo=1;
do{
counter++;
printf("the current value2 is %d \n",SDL_SemValue(sem));
fflush(stdout);
SDL_SemWait(sem);
SDL_mutexP(mutex);
if(header.next !=NULL)
temp=header.next ;//move next
memcpy(mp3buf,temp->data,temp->data_len);
SDL_mutexV(mutex);
if(temp->data_len >0)
ret = lame_decode1_headers(mp3buf, temp->data_len , Buffer[0], Buffer[1], &mp3data);
header.next =temp->next ;
if(temp->data!=NULL)
{ printf("free temp->data now");
free(temp->data);
}
if(temp!=NULL)
{
printf("free temp now");
free(temp);
}
memcpy(&pcmBuffer[index],Buffer[0] ,ret);
index+=ret ;
}while(index+500<MAXPCM);
file://}while(counter<40);
}
static void audioCallback(void *unused, Uint8 *stream, int len)
{
#ifdef OLD
Uint8 *waveptr;
int waveleft;
/* Set up the pointers */
waveptr = sound + soundpos;
waveleft = soundlen - soundpos;
/* Go! */
SDL_mutexP(mutex);
while ( waveleft <= len ) {
SDL_MixAudio(stream, waveptr, waveleft, SDL_MIX_MAXVOLUME);
stream += waveleft;
len -= waveleft;
waveptr = sound;
waveleft = soundlen;
soundpos = 0;
}
SDL_MixAudio(stream, waveptr, len, SDL_MIX_MAXVOLUME);
SDL_mutexV(mutex);
soundpos += len;
#else
if(soundlen<=0)
return;
len=(len>soundlen?soundlen:len);
printf("the callback return len=%d\n",len);
SDL_MixAudio(stream,sound,len,SDL_MIX_MAXVOLUME);
sound+=len;
soundlen-=len;
#endif
}
/*the callback function of thread player*/
static int playerCallback(void *data)
{
int lameret=0;
SDL_AudioSpec *desired, *obtained;
/* Allocate a desired SDL_AudioSpec */
desired=(SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec));
/* Allocate space for the obtained SDL_AudioSpec */
obtained=(SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec));
/* 22050Hz - FM Radio quality */
desired->freq=22050;
/* 16-bit signed audio */
desired->format=AUDIO_S16LSB;
/* Mono */
desired->channels=1;
/* Large audio buffer reduces risk of dropouts but increases response time */
desired->samples=8192;
/* Our callback function */
desired->callback=audioCallback;
desired->userdata=NULL;
if ( SDL_OpenAudio(desired,obtained) < 0 ) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
exit(2);
}
free(desired);
printf("I have walk into player thread and going to prepareBuffer\n");
/*prepare data mainly get rid of the queue and add it to a big buffer*/
SDL_Delay(4000);
printf("delay ok! going to prepare buffer");
lameret=lame_decode_init();
printf("lame decode init ret %d\n",lameret);
while(1)
{
prepareBuffer();
sound=pcmBuffer;
soundpos=0;
soundlen=MAXPCM-500;
SDL_PauseAudio(0);
}
/* Let the audio run */
// printf("Using audio driver: %s\n", SDL_AudioDriverName(name, 32));
while (1 )
SDL_Delay(1000);
/* Clean up on signal */
SDL_CloseAudio();
}
/* ------------------------------------------------------------------------- */
/* Main loop: parses command line and initializes RTP session */
int main(int argc,char* argv[])
{
int32_t ac, filter_me = 0, send_enable = 0;
char *address = NULL;
uint16_t port = 0;
SDL_Thread * reciever;
SDL_Thread * player;
int init_sem=0;
ac = 1;
while (argv[ac][0] == '-') {
switch(tolower(argv[ac][1])) {
case 'f':
filter_me = 1;
break;
case 'l':
send_enable = 0;
break;
}
ac++;
}
if (argc - ac != 2) {
usage();
}
address = argv[ac];
port = atoi(argv[ac + 1]);
if ( SDL_Init(0) < 0 )
{ fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
sem = SDL_CreateSemaphore(init_sem);
if ( (mutex=SDL_CreateMutex()) == NULL )
{ fprintf(stderr, "Couldn't create mutex: %s\n", SDL_GetError());
exit(1);
}
reciever = SDL_CreateThread(recieverCallback,address);
player= SDL_CreateThread(playerCallback,"player");
SDL_WaitThread(reciever, NULL);
SDL_WaitThread(player, NULL);
return 0;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://icculus.org/pipermail/sdlsound/attachments/20030120/c9eb4fd4/attachment.htm>
More information about the sdlsound
mailing list