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

📄 audiolib.c

📁 Motion JPEG编解码器源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Small library for reading and writing audio.    This library forks an audio task and communicates with it    via a shared memory segment.    All what this library does can be done in principal    with ordinary read/write calls on the sound device.    The Linux audio driver uses so small buffers, however,    that overruns/underruns are unavoidable in many cases.    Copyright (C) 2000 Rainer Johanni <Rainer@Johanni.de>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#ifdef HAVE_CONFIG_H#include "../config.h"#endif#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <signal.h>#include <string.h>#include <errno.h>#ifdef HAVE_SYS_SOUNDCARD_H#include <sys/soundcard.h>#endif#include <sys/time.h>#include <sys/resource.h>#include <sys/mman.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/ioctl.h>/* The shared memory things */#include <sys/ipc.h>#include <sys/shm.h>#ifndef FORK_NOT_THREAD#include <pthread.h>#endif#include "mjpeg_logging.h"#include "audiolib.h"#ifdef FORK_NOT_THREADstatic int pid; /* pid of child */static int shm_seg;#elsestatic pthread_t capture_thread;#endif#define TIME_STAMP_TOL 100000  /* tolerance for timestamps in us */#define N_SHM_BUFFS 256 /* Number of buffers, must be a power of 2 */#define SHM_BUFF_MASK (N_SHM_BUFFS-1)/* #define BUFFSIZE (8192) *//* A.Stevens Jul 2000: Several drivers for modern PCI cards can't deliver   frags larger than 4096 so lets not even try for 8192 byte buffer chunks*/#define BUFFSIZE (4096)#define NBUF(x) ((x)&SHM_BUFF_MASK)struct shm_buff_s{   volatile uint8_t audio_data[N_SHM_BUFFS][BUFFSIZE];   volatile int used_flag[N_SHM_BUFFS];   volatile struct timeval tmstmp[N_SHM_BUFFS];   volatile int status[N_SHM_BUFFS];   volatile int exit_flag;    /* set by parent */   volatile int audio_status; /* set by audio task */   volatile int audio_start;  /* trigger start in playing */   volatile char error_string[4096];} *shmemptr;static int audio_buffer_size = BUFFSIZE;    /* The buffer size actually used *//* The parameters for audio capture/playback */static int initialized=0;static int audio_capt;           /* Flag for capture/playback */static int mmap_capt;            /* Flag for mmap/read capture */static int stereo;               /* 0: capture mono, 1: capture stereo */static int audio_size;           /* size of an audio sample: 8 or 16 bits */static int audio_rate;           /* sampling rate for audio */static int audio_byte_rate;           /* sampling rate for audio Bps*//* Buffer counter */static int n_audio;/* Bookkeeping of the write buffers */static char audio_left_buf[BUFFSIZE];  static int audio_bytes_left;   /* Number of bytes in audio_left_buf */static unsigned int n_buffs_output, n_buffs_error;static struct timeval buffer_timestamp;static int usecs_per_buff;/* Forward declarations: */void do_audio(void);char *audio_strerror(void);void set_timestamp(struct timeval tmstmp);void swpcpy(char *dst, char *src, int num);typedef void *(*start_routine_p)(void *);/* some (internally used only) error numbers */static int audio_errno = 0;#define AUDIO_ERR_INIT     1  /* Not initialized */#define AUDIO_ERR_INIT2    2  /* allready initialized */#define AUDIO_ERR_ASIZE    3  /* audio size not 8 or 16 */#define AUDIO_ERR_SHMEM    4  /* Error getting shared memory segment */#define AUDIO_ERR_FORK     5  /* Can not fork audio task */#define AUDIO_ERR_MODE     6  /* Wrong read/write mode */#define AUDIO_ERR_BSIZE    7  /* Buffer size for read too small */#define AUDIO_ERR_TMOUT    8  /* Timeout waiting for audio */#define AUDIO_ERR_BOVFL    9  /* Buffer overflow when writing */#define AUDIO_ERR_ATASK   99  /* Audio task died - more in shmemptr->error_string */static char errstr[4096];char *audio_strerror(void){   switch(audio_errno)   {      case 0:         strcpy(errstr,"No Error");         break;      case AUDIO_ERR_INIT:         strcpy(errstr,"Audio not initialized");         break;      case AUDIO_ERR_INIT2:         strcpy(errstr,"audio_init called but audio allready initialized");         break;      case AUDIO_ERR_ASIZE:         strcpy(errstr,"audio sample size not 8 or 16");         break;      case AUDIO_ERR_SHMEM:         strcpy(errstr,"Audio: Error getting shared memory segment");         break;      case AUDIO_ERR_FORK:         strcpy(errstr,"Can not fork audio task");         break;      case AUDIO_ERR_MODE:         strcpy(errstr,"Audio: Wrong read/write mode");         break;      case AUDIO_ERR_BSIZE:         strcpy(errstr,"Audio: Buffer size for read too small");         break;      case AUDIO_ERR_TMOUT:         strcpy(errstr,"Timeout waiting for audio initialization");         break;      case AUDIO_ERR_BOVFL:         strcpy(errstr,"Buffer overflow writing audio");         break;      case AUDIO_ERR_ATASK:         sprintf(errstr,"Audio task died. Reason: %s",shmemptr->error_string);         break;      default:         strcpy(errstr,"Audio: Unknown error");   }   return errstr;}/* * audio_init: Initialize audio system. * *      a_read     0: User is going to write (output) audio *                 1: User is going to read (input) audio *      a_stereo   0: mono, 1: stereo *      a_size     size of an audio sample: 8 or 16 bits *      a_rate     sampling rate for audio * *      returns 0 for success, -1 for failure * */int audio_init(int a_read, int use_read, int a_stereo, int a_size, int a_rate){   int i;   /* Check if the audio task is allready initialized */   if(initialized) { audio_errno = AUDIO_ERR_INIT2; return -1; }   /* Checks of parameters */   if (a_size != 8 && a_size != 16) { audio_errno = AUDIO_ERR_ASIZE; return -1; }   if( use_read )	   mjpeg_info( "Using read(2) system call for capture");   else	   mjpeg_info( "Using mmap(2) system call for capture");   /* Copy our parameters into static space */   audio_capt = a_read;   mmap_capt  = !use_read;   stereo     = a_stereo;   audio_size = a_size;   audio_rate = a_rate;   /* Reset counters */   n_audio = 0;   audio_bytes_left = 0;   n_buffs_output   = 0;   n_buffs_error    = 0;   buffer_timestamp.tv_sec  = 0;   buffer_timestamp.tv_usec = 0;   /*    * Calculate bytes/second of the audio stream    */   audio_byte_rate = audio_rate;   if (stereo)         audio_byte_rate *= 2;   if (audio_size==16) audio_byte_rate *= 2;   /* Set audio buffer size */   audio_buffer_size = BUFFSIZE;   /* A.Stevens Jul 2000 modified to allow cards with max frag size of	  4096.... if(tmp<88200) audio_buffer_size = 4096; */   if(audio_byte_rate<44100) audio_buffer_size = BUFFSIZE/2;   if(audio_byte_rate<22050) audio_buffer_size = BUFFSIZE/4;   /* Do not change the following calculations,      they are this way to avoid overflows ! */   usecs_per_buff  = audio_buffer_size*100000/audio_byte_rate;   usecs_per_buff *= 10;#ifdef FORK_NOT_THREAD   /* Allocate shared memory segment */   shm_seg = shmget(IPC_PRIVATE, sizeof(struct shm_buff_s), IPC_CREAT | 0777);   if(shm_seg < 0) { audio_errno = AUDIO_ERR_SHMEM; return -1; }   /* attach the segment and get its address */   shmemptr = (struct shm_buff_s *) shmat(shm_seg,0,0);   if(shmemptr < 0) { audio_errno = AUDIO_ERR_SHMEM; return -1; }   /* mark the segment as destroyed, it will be removed after      the last process which had attached it is gone */   if( shmctl( shm_seg, IPC_RMID, (struct shmid_ds *)0 ) == -1 )   {      audio_errno = AUDIO_ERR_SHMEM;      return -1;   }#else   shmemptr = (struct shm_buff_s *) malloc(sizeof(struct shm_buff_s));   if( shmemptr == NULL )	  { audio_errno = AUDIO_ERR_SHMEM; return -1; }#endif   /* set the flags in the shared memory */   for(i=0;i<N_SHM_BUFFS;i++) shmemptr->used_flag[i] = 0;   for(i=0;i<N_SHM_BUFFS;i++) shmemptr->status[i]    = 0;   shmemptr->exit_flag    = 0;   shmemptr->audio_status = 0;   shmemptr->audio_start  = 0;   /* do the fork */#ifdef FORK_NOT_THREAD   pid = fork();   if(pid<0)   {      audio_errno = AUDIO_ERR_FORK;      return -1;   }   /* the child goes into the audio task */   if (pid==0)   {      /* The audio buffers in Linux are ridiculosly small,         therefore the audio task must have a high priority,         This call will fail if we are not superuser, we don't care.       */      setpriority(PRIO_PROCESS, getpid(), -20);      /* Ignore SIGINT while capturing, the parent wants to catch it */      if(audio_capt) signal(SIGINT,SIG_IGN);      do_audio();      exit(0);   }#else      if( pthread_create( &capture_thread, NULL, (start_routine_p)do_audio, NULL) )	 {	   audio_errno = AUDIO_ERR_FORK;	   return -1;	 }   #endif   /* Since most probably errors happen during initialization,      we wait until the audio task signals either success or failure */   for(i=0;;i++)   {      /* Check for timeout, 10 Seconds should be plenty */      if(i>1000)      {#ifdef FORK_NOT_THREAD         kill(pid,SIGKILL);         shmemptr->exit_flag = 1;         waitpid(pid,0,0);#else         shmemptr->exit_flag = 1;		 pthread_cancel( capture_thread );		 pthread_join( capture_thread, NULL );#endif         audio_errno = AUDIO_ERR_TMOUT;         return -1;      }      if(shmemptr->audio_status<0)      {         audio_errno = AUDIO_ERR_ATASK;         return -1;      }      if(shmemptr->audio_status>0) break;      usleep(10000);   }   initialized = 1;   return 0;}/* * audio_shutdown: Shutdown audio system * * It is important that this routine is called whenever the host * program finished, or else there will be the audio task * left over, having the sound device still opened and preventing * other programs from using sound. * */void audio_shutdown(void){   if(!initialized) return;   /* show the child we want to exit */   shmemptr->exit_flag = 1;#ifdef FORK_NOT_THREAD   waitpid(pid,0,0);#else   pthread_join( capture_thread, NULL );#endif   initialized = 0;}long audio_get_buffer_size(void){   return audio_buffer_size;}/* * audio_start: Actually trigger the start of audio after all *              initializations have been done. *              Only for playing! * *      returns 0 for success, -1 for failure */void audio_start(void){   /* signal the audio task that we want to start */   shmemptr->audio_start = 1;}/* * set_timestamp: * Set buffer timestamp either to the value of the tmstmp parameter * or calculate it from previous value */voidset_timestamp(struct timeval tmstmp){   if( tmstmp.tv_sec != 0 )   {      /* Time stamp is realiable */      buffer_timestamp = tmstmp;   }   else   {      /* Time stamp not reliable - calculate from previous */      if(buffer_timestamp.tv_sec != 0)      {         buffer_timestamp.tv_usec += usecs_per_buff;         while(buffer_timestamp.tv_usec>=1000000)         {            buffer_timestamp.tv_usec -= 1000000;            buffer_timestamp.tv_sec  += 1;         }      }   }}/* * swpcpy: like memcpy, but bytes are swapped during copy */void swpcpy(char *dst, char *src, int num){   int i;   num &= ~1; /* Safety first */   for(i=0;i<num;i+=2)   {      dst[i  ] = src[i+1];      dst[i+1] = src[i  ];   }}/* * audio_read: Get audio data, if available *             Behaves like a nonblocking read * *    buf      Buffer where to copy the data *    size     Size of the buffer *    swap     Flag if to swap the endian-ness of 16 bit data *    tmstmp   returned: timestamp when buffer was finished reading *                       contains 0 if time could not be reliably determined *    status   returned: 0 if buffer is corrupted *                       1 if buffer is ok. *             tmstmp and status are set only if something was read * *    returns  the number of bytes in the buffer, *             0 if nothing available *            -1 if an error occured * */int audio_read( uint8_t *buf, int size, int swap, 			    struct timeval *tmstmp, int *status){   if(!initialized) { audio_errno = AUDIO_ERR_INIT; return -1; }   /* 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; }   if(size<audio_buffer_size) { audio_errno = AUDIO_ERR_BSIZE; return -1; }   /* Check if a new audio sample is ready */   if(shmemptr->used_flag[NBUF(n_audio)])   {      /* Got an audio sample, copy it to the output buffer */      if(swap && audio_size==16)         swpcpy((void*)buf,(void*)shmemptr->audio_data[NBUF(n_audio)],audio_buffer_size);      else         memcpy((void*)buf,(void*)shmemptr->audio_data[NBUF(n_audio)],audio_buffer_size);      /* set the other return values */      set_timestamp(shmemptr->tmstmp[NBUF(n_audio)]);      if(tmstmp) *tmstmp = buffer_timestamp;      if(status) *status = shmemptr->status[NBUF(n_audio)] > 0;            /* reset used_flag, increment n-audio */      shmemptr->status[NBUF(n_audio)]    = 0;      shmemptr->used_flag[NBUF(n_audio)] = 0;      n_audio++;      return audio_buffer_size;   }   return 0;}static void update_output_status(void){   while(shmemptr->status[NBUF(n_buffs_output)])   {      if(shmemptr->status[NBUF(n_buffs_output)] < 0) n_buffs_error++;      set_timestamp(shmemptr->tmstmp[NBUF(n_buffs_output)]);      shmemptr->status[NBUF(n_buffs_output)] = 0;      n_buffs_output++;   }}void audio_get_output_status(struct timeval *tmstmp, unsigned int *nb_out, unsigned int *nb_err){   if(tmstmp) *tmstmp = buffer_timestamp;   if(nb_out) *nb_out = n_buffs_output;   if(nb_err) *nb_err = n_buffs_error;}   /* * audio_write: Buffer audio data for output *              Behaves like a nonblocking write * *    buf       Buffer with audio data *    size      Size of the buffer *    swap      Flag if to swap the endian-ness of 16 bit data * *    returns   the number of bytes actually written *              -1 if an error occured * *              If the number of bytes actually written is smaller *              than size, the audio ringbuffer is completely filled * */int audio_write(uint8_t *buf, int size, int swap){   int nb;   if(!initialized) { audio_errno = AUDIO_ERR_INIT; return -1; }

⌨️ 快捷键说明

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