⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audiolib.c

📁 Motion JPEG编解码器源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
   /* Is audio task still ok ? */   if(shmemptr->audio_status < 0) { audio_errno = AUDIO_ERR_ATASK; return -1; }   if(audio_capt) { audio_errno = AUDIO_ERR_MODE;  return -1; }   update_output_status();   /* If the number of bytes we got isn't big enough to fill      the next buffer, copy buf into audio_left_buf */   if (audio_bytes_left+size < audio_buffer_size)   {      memcpy(audio_left_buf+audio_bytes_left,buf,size);      audio_bytes_left += size;      return size;   }   nb = 0;   /* if audio_left_buf contains something, output that first */   if (audio_bytes_left)   {      memcpy(audio_left_buf+audio_bytes_left,buf,audio_buffer_size-audio_bytes_left);      if(shmemptr->used_flag[NBUF(n_audio)])      {         audio_errno = AUDIO_ERR_BOVFL;         return -1;      }      if(swap && audio_size==16)         swpcpy((void*)shmemptr->audio_data[NBUF(n_audio)],audio_left_buf,audio_buffer_size);      else         memcpy((void*)shmemptr->audio_data[NBUF(n_audio)],audio_left_buf,audio_buffer_size);      shmemptr->used_flag[NBUF(n_audio)] = 1;      nb = audio_buffer_size-audio_bytes_left;      audio_bytes_left = 0;      n_audio++;   }   /* copy directly to the shmem buffers */   while(size-nb >= audio_buffer_size)   {      if(shmemptr->used_flag[NBUF(n_audio)])      {         audio_errno = AUDIO_ERR_BOVFL;         return -1;      }      if(swap && audio_size==16)         swpcpy((void*)shmemptr->audio_data[NBUF(n_audio)],(void*)(buf+nb),audio_buffer_size);      else         memcpy((void*)shmemptr->audio_data[NBUF(n_audio)],(void*)(buf+nb),audio_buffer_size);      shmemptr->used_flag[NBUF(n_audio)] = 1;      nb += audio_buffer_size;      n_audio++;   }   /* copy the remainder into audio_left_buf */   if(nb<size)   {      audio_bytes_left = size-nb;      memcpy(audio_left_buf,buf+nb,audio_bytes_left);   }   return size;}/* * The audio task */#ifdef HAVE_SYS_SOUNDCARD_Hstatic void system_error(const char *str, int fd, int use_strerror){   if(use_strerror)      sprintf((char*)shmemptr->error_string, "Error %s - %s",str,strerror(errno));   else      sprintf((char*)shmemptr->error_string, "Error %s",str);   shmemptr->audio_status = -1;   if( fd >= 0 )	   close(fd);#ifdef FORK_NOT_THREAD      exit(1);#else	  pthread_exit(NULL);#endif}#endif /* HAVE_SYS_SOUNDCARD_H */#ifdef HAVE_SYS_SOUNDCARD_Hvoid do_audio(void){   int fd = -1;   int tmp, ret, caps, afmt, frag;   int nbdone, nbque, ndiff, nbpend, nbset, maxdiff;   uint8_t *buf = NULL;   fd_set selectset;   struct count_info count;   struct audio_buf_info info;   struct timeval tv;   const char *audio_dev_name;#ifndef FORK_NOT_THREAD   struct sched_param schedparam;   sigset_t blocked_signals;   /* Set the capture thread in a reasonable state - cancellation enabled      and asynchronous, SIGINT's ignored... */   /* PTHREAD_CANCEL_ASYNCHRONOUS is evil. *//*   if( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL) )   {      system_error( "Bad pthread_setcancelstate", fd, 0 );   }   if( pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL) )   {      system_error( "Bad pthread_setcanceltype", fd, 0 );   }*/   sigaddset( &blocked_signals, SIGINT );   if( pthread_sigmask( SIG_BLOCK, &blocked_signals, NULL ))   {      system_error( "Bad pthread_sigmask", fd, 0 );   }#endif	 /* * Fragment size and max possible number of frags */    switch (audio_buffer_size)   {   case 8192: frag = 0x7fff000d; break;   case 4096: frag = 0x7fff000c; break;   case 2048: frag = 0x7fff000b; break;   case 1024: frag = 0x7fff000a; break;   default:	 system_error("Audio internal error - audio_buffer_size",fd,0);   }   /* if somebody plays with BUFFSIZE without knowing what he does ... */   if (audio_buffer_size>BUFFSIZE)      system_error("Audio internal error audio_buffer_size > BUFFSIZE",fd,0);/* * Open Audio device, set number of frags wanted */   audio_dev_name = getenv("LAV_AUDIO_DEV");   if(!audio_dev_name) audio_dev_name = "/dev/dsp";   if(audio_capt)      fd=open(audio_dev_name, O_RDONLY, 0);   else      fd=open(audio_dev_name, O_RDWR,   0);   if (fd<0) system_error(audio_dev_name,fd,1);   ret = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);   if(ret<0) system_error("in ioctl SNDCTL_DSP_SETFRAGMENT", fd, 1);/* * Setup sampling parameters. */   afmt = (audio_size==16) ? AFMT_S16_LE : AFMT_U8;   tmp = afmt;   ret = ioctl(fd, SNDCTL_DSP_SETFMT, &tmp);   if(ret<0 || tmp!=afmt) system_error("setting sound format",fd,0);   tmp = stereo; /* 0=mono, 1=stereo */   ret = ioctl(fd, SNDCTL_DSP_STEREO, &tmp);   if(ret<0 || tmp!=stereo) system_error("setting mono/stereo",fd,0);   tmp = audio_rate;   ret = ioctl(fd, SNDCTL_DSP_SPEED, &tmp);   if(ret<0) {       system_error("setting sound rate",fd,0);   } else if(tmp != audio_rate) {       mjpeg_warn("Sound card told us it's using rate %dHz instead of %dHz", tmp, audio_rate);   }/* Calculate number of bytes corresponding to TIME_STAMP_TOL */   maxdiff = audio_byte_rate / (1000000/TIME_STAMP_TOL);/* * Check that the device has capability to do mmap and trigger */   ret = ioctl(fd, SNDCTL_DSP_GETCAPS, &caps);   if(ret<0) system_error("getting audio device capabilities",fd,1);   if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP))      system_error("Soundcard cant do mmap or trigger",fd,0);/* * Get the size of the input/output buffer and do the mmap */   if (audio_capt)      ret = ioctl(fd, SNDCTL_DSP_GETISPACE, &info);   else      ret = ioctl(fd, SNDCTL_DSP_GETOSPACE, &info);   if(ret<0) system_error("in ioctl SNDCTL_DSP_GET[IO]SPACE",fd,1);   if (info.fragsize != audio_buffer_size)      system_error("Soundcard fragment size unexpected",fd,0);/* * Original comment: * Normally we should get at least 8 fragments (if we use 8KB buffers) * or even more if we use 4KB od 2 KB buffers * We consider 4 fragments as the absolut minimum here! *  * A.Stevens Jul 2000: I'm a bit puzzled by the above.  A 4096 byte * buffer takes 1/20th second to fill at 44100 stereo.  So provide we * empty one frag in less than this we should be o.k. hardly onerous. * Presumably the problem was that this code wasn't running real-time * and so could get starved on a load system. * Anyway, insisting on 8 frags of 8192 bytes puts us sure out of luck * drivers for quite a few modern PCI soundcards ... so lets try for 2 * and see what real-time scheduling can do! */   if (info.fragstotal < 2)   {	   system_error("Could not get enough audio buffer fragments",fd,0);   }   tmp = info.fragstotal*info.fragsize;   if( !audio_capt || mmap_capt )   {	   if (audio_capt)		   buf=mmap(NULL, tmp, PROT_READ , MAP_SHARED, fd, 0);	   else		   buf=mmap(NULL, tmp, PROT_WRITE, MAP_SHARED, fd, 0);	   if (buf==MAP_FAILED)		   system_error("mapping audio buffer",fd, 1);	   	   /*		* Put device into hold		*/	   tmp = 0;	   ret = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);	   if(ret<0) system_error("in ioctl SNDCTL_DSP_SETTRIGGER",fd,1);   }/* * Signal the parent that initialization is done */   shmemptr->audio_status = 1;/* * nbdone is the number of buffers processed by the audio driver *        so far (ie. the number of buffers read or written) * nbque  is the number of buffers which have been queued so far *        for playing (not used in audio capture) * nbset  Number of buffers set (with real data or 0s) * * If we do playback: Wait until the first buffer arrives */   nbdone = 0;   nbque  = 0;   nbset  = 0;   if(!audio_capt)   {      while(!shmemptr->audio_start)      {         usleep(10000);         if(shmemptr->exit_flag)		 {#ifndef FORK_NOT_THREAD			 exit(0);#else			 pthread_exit(NULL);#endif		 }      }      /* Copy as many buffers as are allready here */      for(nbque=0;nbque<info.fragstotal;nbque++)      {         if(!shmemptr->used_flag[NBUF(nbque)]) break;         memcpy(buf+nbque*info.fragsize,                (void*) shmemptr->audio_data[NBUF(nbque)],                info.fragsize);         /* Mark the buffer as free */         shmemptr->used_flag[NBUF(nbque)] = 0;      }      for(nbset=nbque;nbset<info.fragstotal;nbset++)         memset(buf+nbset*info.fragsize,0,info.fragsize);   }#ifndef FORK_NOT_THREAD   /* Now we're ready to go move to Real-time scheduling... */   schedparam.sched_priority = 1;   if(setpriority(PRIO_PROCESS, 0, -20)) { /* Give myself maximum priority */       mjpeg_warn("Unable to set negative priority for audio thread.");   }   if( (ret = pthread_setschedparam( pthread_self(), SCHED_FIFO, &schedparam ) ) ) {      mjpeg_warn("Pthread Real-time scheduling for audio thread could not be enabled.");    }#endif/* * Fire up audio device for mmap capture playback (not necessary for read) */   if( !audio_capt || mmap_capt )   {	   if(audio_capt)		   tmp = PCM_ENABLE_INPUT;	   else		   tmp = PCM_ENABLE_OUTPUT;	   ret = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);	   if(ret<0) system_error("in ioctl SNDCTL_DSP_SETTRIGGER",fd,1);   }   /* The recording/playback loop */   while(1)   {      /* Wait until new audio data can be read/written */	   if( !audio_capt || mmap_capt )	   {		   FD_ZERO(&selectset);		   FD_SET(fd, &selectset);           retry:		   if(audio_capt)			   ret = select(fd+1, &selectset, NULL, NULL, NULL);		   else 			   ret = select(fd+1, NULL, &selectset, NULL, NULL);		   		   if(ret<0)                   {                           if (errno == EINTR)                                goto retry;                           else                                system_error("waiting on audio with select",fd,1);                   }	   }	   else	   {		   if( read(fd, (void *)shmemptr->audio_data[NBUF(nbdone)], info.fragsize ) 			   != info.fragsize )		   {			   system_error( "Sound driver returned partial fragment!\n", fd,1 );		   }	   }      /* Get time - this time is after at least one buffer has been         recorded/played (because select did return), and before the         the audio status obtained by the following ioctl */      gettimeofday(&tv,NULL);      /* Get the status of the sound buffer */	  usleep(1000);      if(audio_capt)         ret = ioctl(fd, SNDCTL_DSP_GETIPTR, &count);      else         ret = ioctl(fd, SNDCTL_DSP_GETOPTR, &count);      if (ret<0) system_error("in ioctl SNDCTL_DSP_GET[IO]PTR",fd,1);      /* Get the difference of minimum number of bytes after the select call         and bytes actually present - this gives us a measure of accuracy         of the time in tv.		 TODO         Note: count.bytes can overflow in extreme situations (more than               3 hrs recording with 44.1 KHz, 16bit stereo), ndiff should               be calculated correctly.      */      ndiff = count.bytes - audio_buffer_size*(nbdone+1);	  /* Uncomment this and run testrec if you're getting audio capture 		 problems...	   */	  /*		mjpeg_info( "CB=%08d ND=%06d BL=%03d NB=%d", count.bytes, ndiff, count.blocks, NBUF(nbdone) );	  */      if(ndiff>maxdiff)	  {		  tv.tv_sec = tv.tv_usec = 0;	  }	  else	  {		  /* Adjust timestamp to take into account delay between sync			 and now indicated by ndiff */		  tv.tv_usec -= ndiff * 1000000 / audio_byte_rate;		  if( tv.tv_usec < 0 )		  {			  tv.tv_usec += 1000000;			  tv.tv_sec -= 1;		  }	  }      if(audio_capt)      {         /* if exit_flag is set, exit immediatly */         if(shmemptr->exit_flag)		   {            shmemptr->audio_status = -1;			close(fd);#ifdef FORK_NOT_THREAD            exit(0);#else			pthread_exit( NULL );#endif         }         /* copy the ready buffers to our audio ring buffer */		 		 if( mmap_capt )			 nbpend = count.blocks;		 else			 nbpend = 1;         while(nbpend)         {            /* Check if buffer nbdone in the ring buffer is free */            if(shmemptr->used_flag[NBUF(nbdone)])               system_error("Audio ring buffer overflow",fd,0);						if( mmap_capt )				memcpy((void*) shmemptr->audio_data[NBUF(nbdone)],					   buf+(nbdone%info.fragstotal)*info.fragsize,					   info.fragsize);            /* Get the status of the sound buffer after copy,               this permits us to see if an overrun occured */            ret = ioctl(fd, SNDCTL_DSP_GETIPTR, &count);            if(ret<0) system_error("in ioctl SNDCTL_DSP_GETIPTR",fd,1);						if( mmap_capt )				nbpend += count.blocks;            /* if nbpend >= total frags, a overrun most probably occured */            shmemptr->status[NBUF(nbdone)] = (nbpend >= info.fragstotal) ? -1 : 1;            shmemptr->tmstmp[NBUF(nbdone)] = tv;            shmemptr->used_flag[NBUF(nbdone)] = 1;            nbdone++;            nbpend--;            /* timestamps of all following buffers are unreliable */            tv.tv_sec = tv.tv_usec = 0;         }      }      else      {         /* Update the number and status of frags(=buffers) already output */         nbpend = count.blocks;         while(nbpend)         {            /* check for overflow of the status flags in the ringbuffer */            if(shmemptr->status[NBUF(nbdone)])               system_error("Audio ring buffer overflow",fd,0);            /* We have a buffer underrun during write if nbdone>=nbque */            shmemptr->tmstmp[NBUF(nbdone)] = tv;            shmemptr->status[NBUF(nbdone)] = (nbdone<nbque) ? 1 : -1;            nbdone++;            nbpend--;            /* timestamps of all following buffers are unreliable */            tv.tv_sec = tv.tv_usec = 0;         }         /* If exit_flag is set and all buffers are played, exit */         if(shmemptr->exit_flag && nbdone >= nbque)         {            shmemptr->audio_status = -1;			close(fd);#ifdef FORK_NOT_THREAD            exit(0);#else			pthread_exit( NULL );#endif         }         /* Fill into the soundcard memory as many buffers            as fit and are available */         while(nbque-nbdone < info.fragstotal)         {            if(!shmemptr->used_flag[NBUF(nbque)]) break;            if(nbque>nbdone)               memcpy(buf+(nbque%info.fragstotal)*info.fragsize,                      (void*) shmemptr->audio_data[NBUF(nbque)],                      info.fragsize);            /* Mark the buffer as free */            shmemptr->used_flag[NBUF(nbque)] = 0;            nbque++;         }         if(nbset<nbque) nbset = nbque;         while(nbset-nbdone < info.fragstotal)         {            memset(buf+(nbset%info.fragstotal)*info.fragsize,0,info.fragsize);            nbset++;         }      }   }}#elsevoid do_audio(){  fprintf(stderr, "ILLEGAL CALL TO do_audio in audiolib.c: NOT IMPLEMENTED IN IRIX !\n");}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -