00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include <fcntl.h>
00004 #include <sys/mman.h>
00005
00006 #include "korebot.h"
00007
00008
00009 void kb_snd_init( snd_t * snd ,
00010 const char * dsp_device ,
00011 const char * mixer_device )
00012 {
00013 strncpy( snd->dsp_device , dsp_device , PATH_MAX );
00014 strncpy( snd->mixer_device , mixer_device , PATH_MAX );
00015 snd->dsp_fd = -1;
00016 snd->mix_fd = -1;
00017 snd->ibuf = NULL;
00018 snd->iend = NULL;
00019 snd->obuf = NULL;
00020 snd->oend = NULL;
00021 snd->fragSize = 0;
00022 snd->fragCount = 0xFFFF;
00023 }
00024
00025
00028 void kb_snd_exit( snd_t * snd )
00029 {
00030
00031 kb_snd_close( snd );
00032 }
00033
00034
00037 int kb_snd_open( snd_t * snd )
00038 {
00039 int format;
00040 int stereo;
00041 audio_buf_info info;
00042
00043 if ( snd->mix_fd == -1 ) {
00044
00045 if ((snd->mix_fd = open( snd->mixer_device , O_RDWR )) < 0 ) {
00046 perror(snd->mixer_device);
00047 kb_snd_close( snd );
00048 return -1;
00049 }
00050 }
00051
00052
00053 if ( snd->dsp_fd == -1 ) {
00054
00055
00056
00057 if ((snd->dsp_fd = open( snd->dsp_device , O_RDWR )) < 0 ) {
00058 perror(snd->dsp_device);
00059 return -1;
00060 }
00061 }
00062
00063 snd->sampleSize = 16;
00064 format = AFMT_S16_LE;
00065
00066 if (ioctl( snd->dsp_fd , SNDCTL_DSP_SETFMT, &format ) < 0 ) {
00067 return -1;
00068 }
00069
00070 if ( format != AFMT_S16_LE ) {
00071 fprintf(stderr, "Bad format\n");
00072 return -1;
00073 }
00074
00075 stereo = 1;
00076
00077 if ( ioctl( snd->dsp_fd , SNDCTL_DSP_STEREO , &stereo ) < 0 ) {
00078 return -1;
00079 }
00080
00081 if ( stereo != 1 ) {
00082 fprintf(stderr, "Not stereo\n");
00083 return -1;
00084 }
00085
00086 snd->nbChannels = 2;
00087
00088 if ( ioctl( snd->dsp_fd ,
00089 SOUND_PCM_READ_CHANNELS ,
00090 &snd->nbChannels ) < 0 ) {
00091 return -1;
00092 }
00093
00094 if ( ioctl( snd->dsp_fd , SNDCTL_DSP_GETOSPACE , &info ) < 0 )
00095 return -1;
00096
00097 snd->bytePerSample = snd->nbChannels * ( snd->sampleSize / 8 );
00098
00099 snd->fragSize = info.fragsize;
00100
00101 snd->fragCount = info.fragstotal;
00102 KB_DEBUG("snd_open", 0, "fragSize=%u fragCount=%u" ,
00103 snd->fragSize , snd->fragCount );
00104
00105 return 1;
00106 }
00107
00108
00111 void kb_snd_close( snd_t * snd )
00112 {
00113 if ( snd->dsp_fd != -1 ) {
00114 close( snd->dsp_fd );
00115 snd->dsp_fd = -1;
00116 }
00117
00118 if ( snd->mix_fd != -1 ) {
00119 close( snd->mix_fd );
00120 snd->mix_fd = -1;
00121 }
00122
00123 if ( snd->ibuf != NULL ) {
00124 kb_snd_doMunmap( snd );
00125 }
00126 }
00127
00128
00131 int kb_snd_doMmap( snd_t * snd )
00132 {
00133 unsigned int size = snd->fragSize * snd->fragCount;
00134
00135 KB_DEBUG( "snd_doMmap", 0, "map size = %u" , size );
00136
00137 if ( snd->ibuf != NULL ) return 0;
00138
00139 if ( snd->dsp_fd >= 0 ) {
00140
00141 if ((snd->ibuf = mmap( NULL , size , PROT_READ ,
00142 MAP_FILE|MAP_SHARED ,
00143 snd->dsp_fd , 0 )) == (void *)-1) {
00144 return -1;
00145 }
00146 }
00147
00148 snd->iend = (short *)((unsigned char *)snd->ibuf + size);
00149 snd->isize = size;
00150
00151 KB_DEBUG( "snd_doMmap", 0, "ibuf=0x%08X isize=0x%08X" ,
00152 snd->ibuf , snd->isize );
00153
00154 if ( snd->dsp_fd >= 0 ) {
00155
00156 if ((snd->obuf = mmap( NULL , size , PROT_WRITE ,
00157 MAP_FILE|MAP_SHARED ,
00158 snd->dsp_fd , 0 )) == (void *)-1) {
00159 return -1;
00160 }
00161 }
00162
00163 snd->oend = (short *)((unsigned char *)snd->obuf + size) ;
00164 snd->osize = size;
00165
00166 KB_DEBUG( "snd_doMmap", 0, "obuf=0x%08X osize=0x%08X" ,
00167 snd->obuf , snd->osize );
00168
00169 return 1;
00170 }
00171
00172
00175 int kb_snd_doMunmap( snd_t * snd )
00176 {
00177 if ( snd->ibuf != NULL ) {
00178 munmap( snd->ibuf , snd->isize );
00179 snd->ibuf = NULL;
00180 snd->iend = NULL;
00181 snd->isize = 0;
00182 }
00183
00184 if ( snd->obuf != NULL ) {
00185 munmap( snd->obuf , snd->osize );
00186 snd->obuf = NULL;
00187 snd->oend = NULL;
00188 snd->osize = 0;
00189 }
00190
00191 return 0;
00192 }
00193
00194
00195 int kb_snd_enableTrigger( snd_t * snd , int mask )
00196 {
00197 int trig = 0;
00198
00199 if ( snd->dsp_fd < 0 )
00200 return -1;
00201
00202 if (ioctl( snd->dsp_fd , SNDCTL_DSP_SETTRIGGER , &trig ) < 0)
00203 return -1;
00204
00205 if ( trig != 0 ) {
00206 fprintf( stderr , "Bad trigger (0x%08X)\n" , trig );
00207 return -1;
00208 }
00209
00210 trig = mask;
00211
00212 if ( ioctl( snd->dsp_fd , SNDCTL_DSP_SETTRIGGER , &trig ) < 0 )
00213 return -1;
00214
00215 if ( trig != mask ) {
00216 fprintf( stderr , "Bad trigger (0x%08X!=0x%08X)\n" ,
00217 trig , mask );
00218 return -1;
00219 }
00220
00221 KB_DEBUG( "snd_enableTrigger", 0, "Enable Trigger Ok");
00222
00223 return 0;
00224 }
00225
00226
00229 int kb_snd_enableFrag( snd_t * snd )
00230 {
00231 int frag;
00232 int pos;
00233 int fragExponent = 0;
00234
00235 if ( snd->dsp_fd < 0 )
00236 return -1;
00237
00238 for (pos=0; pos<32; pos++) {
00239 if ( snd->fragSize & (1<<pos)) {
00240 fragExponent = pos;
00241 break;
00242 }
00243 }
00244
00245 KB_DEBUG( "snd_enableFrag", 0, "fragExponent = %u" , fragExponent );
00246
00247 frag = ( snd->fragCount << 16 ) | ( fragExponent );
00248
00249 if ( ioctl( snd->dsp_fd , SNDCTL_DSP_SETDUPLEX , 0 ) < 0 ) {
00250 KB_ERROR("snd_enableFrag", KB_ERROR_DUPLEX);
00251 return -1;
00252 }
00253
00254 if ( ioctl( snd->dsp_fd , SNDCTL_DSP_SETFRAGMENT , &frag ) < 0 ) {
00255 KB_ERROR("snd_enableFrag", KB_ERROR_FRAGMENT );
00256 return -1;
00257 }
00258
00259 if (( frag & 0xFFFF) != fragExponent ) {
00260 KB_ERROR("snd_enableFrag",KB_ERROR_FRAGEXP , fragExponent , (frag&0xffff));
00261 return -1;
00262 }
00263
00264 KB_DEBUG( "snd_enableFrag", 0, "EnableFragment Ok");
00265
00266 return 1;
00267 }
00268
00269
00270
00271 short *kb_snd_getIPtr( snd_t * snd )
00272 {
00273 count_info info;
00274 unsigned char *ptr;
00275
00276 if ( snd->dsp_fd < 0 )
00277 return NULL;
00278
00279 if ( ioctl( snd->dsp_fd , SNDCTL_DSP_GETIPTR , &info ) < 0 ) {
00280 KB_ERROR( "snd_getIPtr", KB_ERROR_IPTR );
00281 return NULL;
00282 }
00283
00284 ptr = (unsigned char *)snd->ibuf;
00285 ptr+= info.ptr;
00286 ptr-= snd->fragSize;
00287 if ( ptr < (unsigned char *)snd->ibuf ) {
00288 ptr += snd->isize;
00289 }
00290
00291 return (short *)ptr;
00292 }
00293
00294
00295
00296 short *kb_snd_getOPtr( snd_t * snd )
00297 {
00298 unsigned char * ptr;
00299 count_info info;
00300
00301 if ( snd->dsp_fd < 0 )
00302 return NULL;
00303
00304 if ( ioctl( snd->dsp_fd , SNDCTL_DSP_GETOPTR , &info ) < 0 ) {
00305 KB_ERROR( "snd_getOPtr", KB_ERROR_OPTR );
00306 return NULL;
00307 }
00308
00309 ptr = (unsigned char *)snd->obuf;
00310 ptr += info.ptr;
00311 ptr += snd->fragSize;
00312 if ( ptr >= (unsigned char *)snd->oend ) {
00313 ptr -= snd->osize;
00314 }
00315
00316 return (short *)ptr;
00317
00318 }
00319
00320
00323 unsigned int kb_snd_getFragSize( snd_t * snd )
00324 {
00325 return snd->fragSize;
00326 }
00327
00328
00331 void kb_snd_copyFragTo( snd_t * snd , short * buf )
00332 {
00333 short * ptr;
00334
00335 ptr = (short*)kb_snd_getIPtr(snd);
00336 if ( ptr != NULL ) {
00337 memcpy( buf , ptr , snd->fragSize );
00338 }
00339 }
00340
00341
00344 void kb_snd_copyFragFrom( snd_t * snd , short * buf )
00345 {
00346 short * ptr;
00347
00348 ptr = (short*)kb_snd_getOPtr( snd );
00349 if ( ptr != NULL ) {
00350 memcpy( ptr , buf , snd->fragSize );
00351 }
00352 }
00353
00354
00358 int kb_snd_setVolume( snd_t * snd ,
00359 unsigned int line ,
00360 unsigned int vol_left ,
00361 unsigned int vol_right )
00362 {
00363 int rc = -1;
00364 int arg = ((vol_left<<8)|vol_right);
00365
00366 if ( snd->mix_fd >= 0 ) {
00367 rc = ioctl( snd->mix_fd , MIXER_WRITE(line) , &arg );
00368 }
00369 return rc;
00370 }
00371
00372
00375 int kb_snd_setSampleRate( snd_t * snd , unsigned int sampleRate )
00376 {
00377 int rc = -1;
00378
00379 KB_DEBUG( "snd_setSampleRate", 0, "SampleRate=%u" , sampleRate );
00380
00381 if ( snd->dsp_fd >= 0 ) {
00382 rc = ioctl( snd->dsp_fd , SNDCTL_DSP_SPEED , &sampleRate );
00383 }
00384 return rc;
00385 }
00386
00387
00390 int kb_snd_waitFrag( snd_t * snd )
00391 {
00392 fd_set set;
00393 int rc = -1;
00394
00395 if ( snd->dsp_fd < 0 )
00396 return -1;
00397
00398 FD_ZERO(&set);
00399 FD_SET( snd->dsp_fd , &set);
00400 while (1) {
00401
00402 if ((rc=select( snd->dsp_fd+1 , NULL , &set , NULL, NULL )) < 0 ) {
00403 if ( errno == EINTR ) continue;
00404 }
00405 return rc;
00406 }
00407 }
00408
00409
00412 void kb_snd_sync( snd_t * snd )
00413 {
00414 if ( snd->dsp_fd >= 0 )
00415 ioctl( snd->dsp_fd , SNDCTL_DSP_SYNC , NULL );
00416 }
00417
00418
00421 int kb_snd_record( snd_t * snd , short * data , unsigned long size )
00422 {
00423 int rc = -1;
00424
00425 if ( snd->dsp_fd >= 0 ) {
00426 rc = read( snd->dsp_fd , (void *)data , size );
00427
00428 if ( rc < 0 ) {
00429 if ( errno == EAGAIN )
00430 rc = 0;
00431 }
00432 }
00433
00434 return rc;
00435 }
00436
00437
00440 int kb_snd_play( snd_t * snd , short * data , unsigned long size )
00441 {
00442 int rc = 0;
00443
00444 if ( snd->dsp_fd >= 0 ) {
00445
00446
00447 rc = write( snd->dsp_fd , (void *)data , size );
00448
00449 kb_snd_flush( snd );
00450
00451 }
00452 return rc;
00453 }
00454
00455
00456
00457 int kb_snd_flush( snd_t * snd )
00458 {
00459 int rc = -1;
00460 if ( snd->dsp_fd >= 0 )
00461 rc=ioctl( snd->dsp_fd , SNDCTL_DSP_POST);
00462 return rc;
00463 }
00464
00465
00466
00467 int kb_snd_reset( snd_t * snd )
00468 {
00469 int rc = -1;
00470 if ( snd->dsp_fd >= 0 )
00471 rc=ioctl( snd->dsp_fd , SNDCTL_DSP_RESET );
00472 return rc;
00473 }
00474
00475
00484 int kb_snd_openDevices( snd_t *snd )
00485 {
00486 int rc;
00487
00488
00489 if((rc= kb_init( 0, NULL )) < 0 )
00490 return 1;
00491
00492 KB_DEBUG( "kb_openDevices", 0, "kb_init Ok");
00493
00494
00495 kb_snd_init( snd , "/dev/sound/dsp" , "/dev/sound/mixer" );
00496
00497
00498 if (kb_snd_open(snd) < 0 ) {
00499 fprintf(stderr , "unable to open sound device\n");
00500 return (1);
00501 }
00502
00503 KB_DEBUG( "kb_openDevices", 0, "kb_snd_init Ok");
00504
00505 return 0;
00506 }
00507
00508
00516 unsigned long kb_smplfromdur(unsigned int duration, unsigned smplrate)
00517 {
00518 return duration*smplrate*2;
00519 }
00520
00521
00522
00530 unsigned long kb_durfromsmpl(unsigned int smplnbr, unsigned smplrate)
00531 {
00532 return smplnbr/smplrate/2;
00533 }
00534
00535
00536
00554 unsigned int kb_snd_fragInit(snd_t *snd, int line1Vol, int line2Vol, int smplRate, int mode)
00555 {
00556 int frag = 0;
00557 int ictl;
00558
00559
00560 switch(mode)
00561 {
00562 case 0 : ictl = PCM_ENABLE_INPUT;
00563 break;
00564 case 1 : ictl = PCM_ENABLE_OUTPUT;
00565 break;
00566 default: ictl = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
00567 }
00568
00569 if(!kb_snd_openDevices(snd)){
00570
00571
00572
00573 kb_snd_setSampleRate( snd , smplRate );
00574
00575
00576 kb_snd_setVolume( snd , SOUND_MIXER_LINE1 , line1Vol, line1Vol );
00577 kb_snd_setVolume( snd , SOUND_MIXER_LINE2 , line2Vol, line2Vol );
00578
00579
00580 kb_snd_enableFrag( snd );
00581 kb_snd_doMmap( snd );
00582
00583
00584 kb_snd_enableTrigger( snd , ictl );
00585
00586
00587 frag = kb_snd_getFragSize( snd );
00588 }
00589
00590
00591 return frag;
00592 }
00593
00594
00595
00603 void kb_snd_fragPlay(snd_t *snd, int fragSize)
00604 {
00605 short *in , *out;
00606
00607
00608 kb_snd_waitFrag( snd );
00609
00610
00611 in = kb_snd_getIPtr( snd );
00612 out = kb_snd_getOPtr( snd );
00613
00614
00615 memcpy( out , in , fragSize );
00616 }
00617