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

📄 alsa.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005 *					All rights reserved * *  This file is part of GPAC / alsa audio output module * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC 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 Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  *		 */#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <poll.h>#include <alsa/asoundlib.h>	      #include <gpac/modules/audio_out.h>typedef struct {	snd_pcm_t *playback_handle;	u32 nb_ch, buf_size, delay, num_buffers, total_duration, block_align;	u32 force_sr;	const char *dev_name;	char *wav_buf;} ALSAContext;static GF_Err ALSA_Setup(GF_AudioOutput*dr, void *os_handle, u32 num_buffers, u32 total_duration){	int err;	const char *opt;	ALSAContext *ctx = (ALSAContext*)dr->opaque;		opt = gf_modules_get_option((GF_BaseInterface *)dr, "ALSA", "ForceSampleRate");	if (opt) ctx->force_sr = atoi(opt);	ctx->dev_name = gf_modules_get_option((GF_BaseInterface *)dr, "ALSA", "DeviceName");	if (!ctx->dev_name) {		ctx->dev_name = "hw:0,0";		gf_modules_set_option((GF_BaseInterface *)dr, "ALSA", "DeviceName", ctx->dev_name);	}	/*test device*/	err = snd_pcm_open(&ctx->playback_handle, ctx->dev_name, SND_PCM_STREAM_PLAYBACK, 0);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot open audio device %s: %s\n", ctx->dev_name, snd_strerror (err)) );		return GF_IO_ERR;	}	ctx->num_buffers = num_buffers;	ctx->total_duration = total_duration;	return GF_OK;}static void ALSA_Shutdown(GF_AudioOutput*dr){	ALSAContext *ctx = (ALSAContext*)dr->opaque;	if (ctx->playback_handle) {		GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[ALSA] Closing alsa output\n") );		snd_pcm_close(ctx->playback_handle);		ctx->playback_handle = NULL;	}	if (ctx->wav_buf) free(ctx->wav_buf);	ctx->wav_buf = NULL;}static GF_Err ALSA_ConfigureOutput(GF_AudioOutput*dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg){	snd_pcm_hw_params_t *hw_params = NULL;	int err;	int nb_bufs, sr, val, period_time;	ALSAContext *ctx = (ALSAContext*)dr->opaque;	if (!ctx) return GF_BAD_PARAM;	/*close device*/	if (ctx->playback_handle) {		snd_pcm_close(ctx->playback_handle);		ctx->playback_handle = NULL;	}	if (ctx->wav_buf) free(ctx->wav_buf);	ctx->wav_buf = NULL;	err = snd_pcm_open(&ctx->playback_handle, ctx->dev_name, SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot open audio device %s: %s\n", ctx->dev_name, snd_strerror (err)) );		return GF_IO_ERR;	}	err = snd_pcm_hw_params_malloc(&hw_params);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot allocate hardware params: %s\n", snd_strerror (err)) );		goto err_exit;	}	err = snd_pcm_hw_params_any(ctx->playback_handle, hw_params);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot initialize hardware params: %s\n", snd_strerror (err)) );		goto err_exit;	}	err = snd_pcm_hw_params_set_access(ctx->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set access type: %s\n", snd_strerror (err)) );		goto err_exit;	}	/*set output format*/	ctx->nb_ch = (int) (*NbChannels);	ctx->block_align = ctx->nb_ch;	if ((*nbBitsPerSample) == 16) {		ctx->block_align *= 2;		err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE);	} else {		err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_U8);	}	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample format: %s\n", snd_strerror (err)) );		goto err_exit;	}	/*set output sample rate*/	if (ctx->force_sr) *SampleRate = ctx->force_sr;	sr = *SampleRate;	err = snd_pcm_hw_params_set_rate_near(ctx->playback_handle, hw_params, SampleRate, 0);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample rate: %s\n", snd_strerror (err)) );		goto err_exit;	}	if (sr != *SampleRate) {		GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] Sample rate %d not supported, using %d instead\n", sr, *SampleRate ) );		sr = *SampleRate;	}	/*set output channels*/	err = snd_pcm_hw_params_set_channels_near(ctx->playback_handle, hw_params, NbChannels);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set channel count: %s\n", snd_strerror (err)) );		goto err_exit;	}	if (ctx->nb_ch != *NbChannels) {		GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] %d channels not supported - using %d instead\n", ctx->nb_ch, *NbChannels ) );		ctx->block_align /= ctx->nb_ch;		ctx->nb_ch = *NbChannels;		ctx->block_align *= ctx->nb_ch;	}	err = snd_pcm_hw_params(ctx->playback_handle, hw_params);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set parameters: %s\n", snd_strerror (err)) );		goto err_exit;	}	/* Set number of buffers*/	snd_pcm_hw_params_get_periods_min(hw_params, &val, 0);	nb_bufs = (ctx->num_buffers>val) ? ctx->num_buffers : val;	err = snd_pcm_hw_params_set_periods_near(ctx->playback_handle, hw_params, &nb_bufs, 0);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set number of HW buffers (%d): %s\n", nb_bufs, snd_strerror(err) ));		goto err_exit;	}	/* Set total buffer size*/	if (ctx->total_duration) {		ctx->buf_size = (sr * ctx->total_duration)/1000;	} else {		ctx->buf_size = 2048;	}	ctx->buf_size /= nb_bufs;	err = snd_pcm_hw_params_set_period_size_near(ctx->playback_handle, hw_params, (snd_pcm_uframes_t *)&ctx->buf_size, 0);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set HW buffer size (%d): %s\n", ctx->buf_size, snd_strerror(err) ));		goto err_exit;	}	/*get complete buffer size*/	snd_pcm_hw_params_get_buffer_size(hw_params, (snd_pcm_uframes_t *)&ctx->buf_size);	ctx->buf_size *= ctx->block_align;	/*get period time*/	snd_pcm_hw_params_get_period_time(hw_params, &period_time, 0);		snd_pcm_hw_params_free (hw_params);	hw_params = NULL;	ctx->delay = (ctx->buf_size*1000) / (sr*ctx->block_align);	/*allocate a single buffer*/	ctx->wav_buf = malloc(ctx->buf_size*sizeof(char));	if(!ctx->wav_buf) return GF_OUT_OF_MEM;	memset(ctx->wav_buf, 0, ctx->buf_size*sizeof(char));	GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[ALSA] Setup %d ch @ %d hz - %d periods of %d us - total buffer size %d - overall delay %d ms\n", ctx->nb_ch, sr, nb_bufs, period_time, ctx->buf_size, ctx->delay));		return GF_OK;err_exit:	if (hw_params) snd_pcm_hw_params_free(hw_params);	snd_pcm_close(ctx->playback_handle);	ctx->playback_handle = NULL;	return GF_IO_ERR;}static void ALSA_WriteAudio(GF_AudioOutput*dr){	u32 written;	snd_pcm_sframes_t nb_frames;	int err;	ALSAContext *ctx = (ALSAContext*)dr->opaque;	/*wait ctx delay for device interrupt*/	err = snd_pcm_wait(ctx->playback_handle, 1);	if (err<0) return;	nb_frames = snd_pcm_avail_update(ctx->playback_handle);	if (nb_frames < 0) {		if (nb_frames == -EPIPE) {			GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] an xrun occured!\n"));			snd_pcm_prepare(ctx->playback_handle);		} else {			GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] unknown ALSA avail update return value (%d)\n", nb_frames));		}		return;	}	if (!nb_frames) return;		//assert(nb_frames*ctx->block_align<=ctx->buf_size);	written = dr->FillBuffer(dr->audio_renderer, ctx->wav_buf, (u32) (ctx->block_align*nb_frames) );	if (!written) return;	written /= ctx->block_align;	err = snd_pcm_writei(ctx->playback_handle, ctx->wav_buf, written);	if (err == -EPIPE ) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] an xrun occured!\n"));		snd_pcm_prepare(ctx->playback_handle);		err = snd_pcm_writei(ctx->playback_handle, ctx->wav_buf, nb_frames);	}	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Write failure: %s\n", snd_strerror(err)));	}}static void ALSA_SetVolume(GF_AudioOutput*dr, u32 Volume){}static void ALSA_SetPan(GF_AudioOutput*dr, u32 Pan) {}static void ALSA_SetPriority(GF_AudioOutput*dr, u32 Priority) {}static u32 ALSA_GetAudioDelay(GF_AudioOutput*dr){	ALSAContext *ctx = (ALSAContext*)dr->opaque;	return ctx->delay;}static GF_Err ALSA_QueryOutputSampleRate(GF_AudioOutput*dr, u32 *desired_sr, u32 *NbChannels, u32 *nbBitsPerSample){	ALSAContext *ctx = (ALSAContext*)dr->opaque;	int err;	snd_pcm_hw_params_t *hw_params = NULL;	err = snd_pcm_hw_params_malloc(&hw_params);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot allocate hardware params: %s\n", snd_strerror (err)) );		goto err_exit;	}	err = snd_pcm_hw_params_any(ctx->playback_handle, hw_params);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot initialize hardware params: %s\n", snd_strerror (err)) );		goto err_exit;	}	err = snd_pcm_hw_params_set_rate_near(ctx->playback_handle, hw_params, desired_sr, 0);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot check available sample rates: %s\n", snd_strerror (err)) );		goto err_exit;	}	err = snd_pcm_hw_params_set_channels_near(ctx->playback_handle, hw_params, NbChannels);	if (err < 0) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot check available channels: %s\n", snd_strerror (err)) );		goto err_exit;	}	snd_pcm_hw_params_free (hw_params);	hw_params = NULL;	return GF_OK;err_exit:	snd_pcm_hw_params_free (hw_params);	hw_params = NULL;	return GF_IO_ERR;}void *NewALSAOutput(){	ALSAContext *ctx;	GF_AudioOutput*driv;	GF_SAFEALLOC(ctx, ALSAContext);	if(!ctx) return NULL;	GF_SAFEALLOC(driv, GF_AudioOutput);	if(!driv) {		free(ctx);		return NULL;	}	driv->opaque = ctx;	driv->SelfThreaded = 0;	driv->Setup = ALSA_Setup;	driv->Shutdown = ALSA_Shutdown;	driv->ConfigureOutput = ALSA_ConfigureOutput;	driv->GetAudioDelay = ALSA_GetAudioDelay;	driv->SetVolume = ALSA_SetVolume;	driv->SetPan = ALSA_SetPan;	driv->SetPriority = ALSA_SetPriority;	driv->QueryOutputSampleRate = ALSA_QueryOutputSampleRate;	driv->WriteAudio = ALSA_WriteAudio;	GF_REGISTER_MODULE_INTERFACE(driv, GF_AUDIO_OUTPUT_INTERFACE, "ALSA Audio Output", "gpac distribution");	return driv;}void DeleteALSAOutput(void *ifce){	GF_AudioOutput*dr = (GF_AudioOutput*) ifce;	ALSAContext *ctx = (ALSAContext *)dr->opaque;	free(ctx);	free(dr);}/* * ******************************************************************** * interface */Bool QueryInterface(u32 InterfaceType){	if (InterfaceType == GF_AUDIO_OUTPUT_INTERFACE) 		return 1;	return 0;}GF_BaseInterface *LoadInterface(u32 InterfaceType){	if (InterfaceType == GF_AUDIO_OUTPUT_INTERFACE) 		return NewALSAOutput();	return NULL;}void ShutdownInterface(GF_BaseInterface *ifce){	if (ifce->InterfaceType==GF_AUDIO_OUTPUT_INTERFACE)		DeleteALSAOutput((GF_AudioOutput*)ifce);}

⌨️ 快捷键说明

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