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