📄 sdl_alsa_audio.c
字号:
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR" */#define SWIZ6(T) \ T *ptr = (T *) mixbuf; \ const Uint32 count = (this->spec.samples / 6); \ Uint32 i; \ for (i = 0; i < count; i++, ptr += 6) { \ T tmp; \ tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \ tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \ }static __inline__ void swizzle_alsa_channels_6_64bit(_THIS) { SWIZ6(Uint64); }static __inline__ void swizzle_alsa_channels_6_32bit(_THIS) { SWIZ6(Uint32); }static __inline__ void swizzle_alsa_channels_6_16bit(_THIS) { SWIZ6(Uint16); }static __inline__ void swizzle_alsa_channels_6_8bit(_THIS) { SWIZ6(Uint8); }#undef SWIZ6/* * Called right before feeding this->mixbuf to the hardware. Swizzle channels * from Windows/Mac order to the format alsalib will want. */static __inline__ void swizzle_alsa_channels(_THIS){ if (this->spec.channels == 6) { const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */ if (fmtsize == 16) swizzle_alsa_channels_6_16bit(this); else if (fmtsize == 8) swizzle_alsa_channels_6_8bit(this); else if (fmtsize == 32) swizzle_alsa_channels_6_32bit(this); else if (fmtsize == 64) swizzle_alsa_channels_6_64bit(this); } /* !!! FIXME: update this for 7.1 if needed, later. */}static void ALSA_PlayAudio(_THIS){ int status; int sample_len; signed short *sample_buf; swizzle_alsa_channels(this); sample_len = this->spec.samples; sample_buf = (signed short *)mixbuf; while ( sample_len > 0 ) { status = SDL_NAME(snd_pcm_writei)(pcm_handle, sample_buf, sample_len); if ( status < 0 ) { if ( status == -EAGAIN ) { SDL_Delay(1); continue; } if ( status == -ESTRPIPE ) { do { SDL_Delay(1); status = SDL_NAME(snd_pcm_resume)(pcm_handle); } while ( status == -EAGAIN ); } if ( status < 0 ) { status = SDL_NAME(snd_pcm_prepare)(pcm_handle); } if ( status < 0 ) { /* Hmm, not much we can do - abort */ this->enabled = 0; return; } continue; } sample_buf += status * this->spec.channels; sample_len -= status; }}static Uint8 *ALSA_GetAudioBuf(_THIS){ return(mixbuf);}static void ALSA_CloseAudio(_THIS){ if ( mixbuf != NULL ) { SDL_FreeAudioMem(mixbuf); mixbuf = NULL; } if ( pcm_handle ) { SDL_NAME(snd_pcm_drain)(pcm_handle); SDL_NAME(snd_pcm_close)(pcm_handle); pcm_handle = NULL; }}static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec){ int status; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_format_t format; snd_pcm_uframes_t frames; Uint16 test_format; /* Open the audio device */ /* Name of device should depend on # channels in spec */ status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if ( status < 0 ) { SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status)); return(-1); } /* Figure out what the hardware is capable of */ snd_pcm_hw_params_alloca(&hwparams); status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams); if ( status < 0 ) { SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); } /* SDL only uses interleaved sample output */ status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if ( status < 0 ) { SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); } /* Try for a closest match on audio format */ status = -1; for ( test_format = SDL_FirstAudioFormat(spec->format); test_format && (status < 0); ) { switch ( test_format ) { case AUDIO_U8: format = SND_PCM_FORMAT_U8; break; case AUDIO_S8: format = SND_PCM_FORMAT_S8; break; case AUDIO_S16LSB: format = SND_PCM_FORMAT_S16_LE; break; case AUDIO_S16MSB: format = SND_PCM_FORMAT_S16_BE; break; case AUDIO_U16LSB: format = SND_PCM_FORMAT_U16_LE; break; case AUDIO_U16MSB: format = SND_PCM_FORMAT_U16_BE; break; default: format = 0; break; } if ( format != 0 ) { status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format); } if ( status < 0 ) { test_format = SDL_NextAudioFormat(); } } if ( status < 0 ) { SDL_SetError("Couldn't find any hardware audio formats"); ALSA_CloseAudio(this); return(-1); } spec->format = test_format; /* Set the number of channels */ status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels); if ( status < 0 ) { status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams); if ( (status <= 0) || (status > 2) ) { SDL_SetError("Couldn't set audio channels"); ALSA_CloseAudio(this); return(-1); } spec->channels = status; } /* Set the audio rate */ status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, spec->freq, NULL); if ( status < 0 ) { SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); } spec->freq = status; /* Set the buffer size, in samples */ frames = spec->samples; frames = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, frames, NULL); spec->samples = frames; SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, 2, NULL); /* "set" the hardware with the desired parameters */ status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams); if ( status < 0 ) { SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); }/* This is useful for debugging... *//*{ snd_pcm_sframes_t bufsize; int fragments; bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams); fragments = SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams); fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments);}*/ /* Set the software parameters */ snd_pcm_sw_params_alloca(&swparams); status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams); if ( status < 0 ) { SDL_SetError("Couldn't get software config: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); } status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 0); if ( status < 0 ) { SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); } status = SDL_NAME(snd_pcm_sw_params_set_avail_min)(pcm_handle, swparams, frames); if ( status < 0 ) { SDL_SetError("Couldn't set avail min: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); } status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams); if ( status < 0 ) { SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status)); ALSA_CloseAudio(this); return(-1); } /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(spec); /* Allocate mixing buffer */ mixlen = spec->size; mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); if ( mixbuf == NULL ) { ALSA_CloseAudio(this); return(-1); } SDL_memset(mixbuf, spec->silence, spec->size); /* Get the parent process id (we're the parent of the audio thread) */ parent = getpid(); /* Switch to blocking mode for playback */ SDL_NAME(snd_pcm_nonblock)(pcm_handle, 0); /* We're ready to rock and roll. :-) */ return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -