1/* 2 * sndio play and grab interface 3 * Copyright (c) 2010 Jacob Meuser 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include <stdint.h> 23#include <sndio.h> 24 25#include "avdevice.h" 26 27#include "sndio_common.h" 28 29static inline void movecb(void *addr, int delta) 30{ 31 SndioData *s = addr; 32 33 s->hwpos += delta * s->channels * s->bps; 34} 35 36av_cold int ff_sndio_open(AVFormatContext *s1, int is_output, 37 const char *audio_device) 38{ 39 SndioData *s = s1->priv_data; 40 struct sio_hdl *hdl; 41 struct sio_par par; 42 43 hdl = sio_open(audio_device, is_output ? SIO_PLAY : SIO_REC, 0); 44 if (!hdl) { 45 av_log(s1, AV_LOG_ERROR, "Could not open sndio device\n"); 46 return AVERROR(EIO); 47 } 48 49 sio_initpar(&par); 50 51 par.bits = 16; 52 par.sig = 1; 53 par.le = SIO_LE_NATIVE; 54 55 if (is_output) 56 par.pchan = s->channels; 57 else 58 par.rchan = s->channels; 59 par.rate = s->sample_rate; 60 61 if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) { 62 av_log(s1, AV_LOG_ERROR, "Impossible to set sndio parameters, " 63 "channels: %d sample rate: %d\n", s->channels, s->sample_rate); 64 goto fail; 65 } 66 67 if (par.bits != 16 || par.sig != 1 || 68 (is_output && (par.pchan != s->channels)) || 69 (!is_output && (par.rchan != s->channels)) || 70 (par.rate != s->sample_rate)) { 71 av_log(s1, AV_LOG_ERROR, "Could not set appropriate sndio parameters, " 72 "channels: %d sample rate: %d\n", s->channels, s->sample_rate); 73 goto fail; 74 } 75 76 s->buffer_size = par.round * par.bps * 77 (is_output ? par.pchan : par.rchan); 78 79 if (is_output) { 80 s->buffer = av_malloc(s->buffer_size); 81 if (!s->buffer) { 82 av_log(s1, AV_LOG_ERROR, "Could not allocate buffer\n"); 83 goto fail; 84 } 85 } 86 87 s->codec_id = par.le ? AV_CODEC_ID_PCM_S16LE : AV_CODEC_ID_PCM_S16BE; 88 s->channels = is_output ? par.pchan : par.rchan; 89 s->sample_rate = par.rate; 90 s->bps = par.bps; 91 92 sio_onmove(hdl, movecb, s); 93 94 if (!sio_start(hdl)) { 95 av_log(s1, AV_LOG_ERROR, "Could not start sndio\n"); 96 goto fail; 97 } 98 99 s->hdl = hdl; 100 101 return 0; 102 103fail: 104 av_freep(&s->buffer); 105 106 if (hdl) 107 sio_close(hdl); 108 109 return AVERROR(EIO); 110} 111 112int ff_sndio_close(SndioData *s) 113{ 114 av_freep(&s->buffer); 115 116 if (s->hdl) 117 sio_close(s->hdl); 118 119 return 0; 120} 121