📄 a2dpd_output_alsa.c
字号:
/*** BlueZ - Bluetooth protocol stack for Linux** Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>*** This library 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.1 of the License, or (at your option) any later version.** This library 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; if not, write to the Free Software* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA**/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <malloc.h>#include <signal.h>#include <string.h>#include <signal.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/select.h>#include <netinet/in.h>#include <alsa/asoundlib.h>#include "a2dpd_output_alsa.h"#include "a2dpd_protocol.h"#include "a2dpd_tools.h"typedef struct snd_pcm_alsa { snd_pcm_t *playback_handle;} snd_pcm_alsa_t;/** Underrun and suspend recovery*/static int xrun_recovery(snd_pcm_t * handle, int err){ if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) DBG("Can't recovery from underrun, prepare failed: %s", snd_strerror(err)); } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume(handle)) == -EAGAIN) { DBG("Suspend flag not released: %s", snd_strerror(err)); usleep(1); /* wait until the suspend flag is released */ } if (err < 0) { err = snd_pcm_prepare(handle); if (err < 0) DBG("Can't recovery from suspend, prepare failed: %s", snd_strerror(err)); } } return err;}int alsa_transfer_raw(LPALSA alsa, const char *pcm_buffer, int pcm_buffer_size){ int result = 0; int errcount = 0;// dump_stream((const short*)pcm_buffer, pcm_buffer_size);begin: result = snd_pcm_writei(alsa->playback_handle, pcm_buffer, pcm_buffer_size / A2DPD_FRAME_BYTES); switch (result) { case -EBADFD: DBG("EBADFD(%d)", result); break; case -EPIPE: DBG("EPIPE(%d)", result); // To manage underrun, we will try to ignore if(errcount<10 && xrun_recovery(alsa->playback_handle, result) == 0) { usleep(1); errcount++; goto begin; } break; case -ESTRPIPE: DBG("ESTRPIPE(%d)", result); if(errcount<10 && xrun_recovery(alsa->playback_handle, result) == 0) { usleep(1); errcount++; goto begin; } break; default: if(result>0) result = result * A2DPD_FRAME_BYTES; break; } return result;}snd_pcm_alsa_t *alsa_alloc(void){ snd_pcm_alsa_t *alsa; alsa = malloc(sizeof(*alsa)); if (!alsa) return NULL; memset(alsa, 0, sizeof(*alsa)); return alsa;}void alsa_free(snd_pcm_alsa_t * alsa){ free(alsa);}void alsa_init(void){}void alsa_exit(void){}LPALSA alsa_new(char *device, int framerate){ DBG(""); snd_pcm_alsa_t *alsa = NULL; snd_pcm_hw_params_t *hw_params = NULL; int bcontinue = 1; char *devname = (device && device[0]) ? device : "plughw:0,0"; DBG("Frame rate is %d", framerate); alsa = alsa_alloc(); if (!alsa) { DBG("Can't allocate"); return NULL; } // Setup alsa bcontinue = bcontinue && (snd_pcm_open(&alsa->playback_handle, devname, SND_PCM_STREAM_PLAYBACK, 0) >= 0); DBG("snd_pcm_open()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_hw_params_malloc(&hw_params) >= 0); DBG("snd_pcm_hw_params_malloc()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_hw_params_any(alsa->playback_handle, hw_params) >= 0); DBG("snd_pcm_hw_params_any()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_hw_params_set_access(alsa->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0); DBG("snd_pcm_hw_params_set_access()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_hw_params_set_format(alsa->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE) >= 0); DBG("snd_pcm_hw_params_set_format()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_hw_params_set_rate(alsa->playback_handle, hw_params, framerate, 0) >= 0); DBG("snd_pcm_hw_params_set_rate()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_hw_params_set_channels(alsa->playback_handle, hw_params, 2) >= 0); DBG("snd_pcm_hw_params_set_channels()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_hw_params(alsa->playback_handle, hw_params) >= 0); DBG("snd_pcm_hw_params()==%d", bcontinue); bcontinue = bcontinue && (snd_pcm_prepare(alsa->playback_handle) >= 0); DBG("snd_pcm_prepare()==%d", bcontinue); // Free if allocated if (hw_params != NULL) snd_pcm_hw_params_free(hw_params); DBG("params freed"); if (!bcontinue) { alsa_destroy(&alsa); } DBG("returning %p", alsa); return alsa;}void alsa_destroy(LPALSA *alsa){ DBG(""); if((*alsa)) { if ((*alsa)->playback_handle != NULL) { snd_pcm_close((*alsa)->playback_handle); } alsa_free(*alsa); *alsa = NULL; } DBG("OK");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -