• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavdevice/pulse.c

Go to the documentation of this file.
00001 /*
00002  * Pulseaudio input
00003  * Copyright (c) 2011 Luca Barbato <lu_zero@gentoo.org>
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * Libav is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00028 #include <pulse/simple.h>
00029 #include <pulse/rtclock.h>
00030 #include <pulse/error.h>
00031 
00032 #include "libavformat/avformat.h"
00033 #include "libavformat/internal.h"
00034 #include "libavutil/opt.h"
00035 
00036 #define DEFAULT_CODEC_ID AV_NE(CODEC_ID_PCM_S16BE, CODEC_ID_PCM_S16LE)
00037 
00038 typedef struct PulseData {
00039     AVClass *class;
00040     char *server;
00041     char *name;
00042     char *stream_name;
00043     int  sample_rate;
00044     int  channels;
00045     int  frame_size;
00046     int  fragment_size;
00047     pa_simple *s;
00048     int64_t pts;
00049     int64_t frame_duration;
00050 } PulseData;
00051 
00052 static pa_sample_format_t codec_id_to_pulse_format(int codec_id) {
00053     switch (codec_id) {
00054     case CODEC_ID_PCM_U8:    return PA_SAMPLE_U8;
00055     case CODEC_ID_PCM_ALAW:  return PA_SAMPLE_ALAW;
00056     case CODEC_ID_PCM_MULAW: return PA_SAMPLE_ULAW;
00057     case CODEC_ID_PCM_S16LE: return PA_SAMPLE_S16LE;
00058     case CODEC_ID_PCM_S16BE: return PA_SAMPLE_S16BE;
00059     case CODEC_ID_PCM_F32LE: return PA_SAMPLE_FLOAT32LE;
00060     case CODEC_ID_PCM_F32BE: return PA_SAMPLE_FLOAT32BE;
00061     case CODEC_ID_PCM_S32LE: return PA_SAMPLE_S32LE;
00062     case CODEC_ID_PCM_S32BE: return PA_SAMPLE_S32BE;
00063     case CODEC_ID_PCM_S24LE: return PA_SAMPLE_S24LE;
00064     case CODEC_ID_PCM_S24BE: return PA_SAMPLE_S24BE;
00065     default:                 return PA_SAMPLE_INVALID;
00066     }
00067 }
00068 
00069 static av_cold int pulse_read_header(AVFormatContext *s,
00070                                      AVFormatParameters *ap)
00071 {
00072     PulseData *pd = s->priv_data;
00073     AVStream *st;
00074     char *device = NULL;
00075     int ret;
00076     enum CodecID codec_id =
00077         s->audio_codec_id == CODEC_ID_NONE ? DEFAULT_CODEC_ID : s->audio_codec_id;
00078     const pa_sample_spec ss = { codec_id_to_pulse_format(codec_id),
00079                                 pd->sample_rate,
00080                                 pd->channels };
00081 
00082     pa_buffer_attr attr = { -1 };
00083 
00084     st = avformat_new_stream(s, NULL);
00085 
00086     if (!st) {
00087         av_log(s, AV_LOG_ERROR, "Cannot add stream\n");
00088         return AVERROR(ENOMEM);
00089     }
00090 
00091     attr.fragsize = pd->fragment_size;
00092 
00093     if (strcmp(s->filename, "default"))
00094         device = s->filename;
00095 
00096     pd->s = pa_simple_new(pd->server, pd->name,
00097                           PA_STREAM_RECORD,
00098                           device, pd->stream_name, &ss,
00099                           NULL, &attr, &ret);
00100 
00101     if (!pd->s) {
00102         av_log(s, AV_LOG_ERROR, "pa_simple_new failed: %s\n",
00103                pa_strerror(ret));
00104         return AVERROR(EIO);
00105     }
00106     /* take real parameters */
00107     st->codec->codec_type  = AVMEDIA_TYPE_AUDIO;
00108     st->codec->codec_id    = codec_id;
00109     st->codec->sample_rate = pd->sample_rate;
00110     st->codec->channels    = pd->channels;
00111     avpriv_set_pts_info(st, 64, 1, 1000000);  /* 64 bits pts in us */
00112 
00113     pd->pts = AV_NOPTS_VALUE;
00114     pd->frame_duration = (pd->frame_size * 1000000LL * 8) /
00115         (pd->sample_rate * pd->channels * av_get_bits_per_sample(codec_id));
00116 
00117     return 0;
00118 }
00119 
00120 static int pulse_read_packet(AVFormatContext *s, AVPacket *pkt)
00121 {
00122     PulseData *pd  = s->priv_data;
00123     int res;
00124     pa_usec_t latency;
00125 
00126     if (av_new_packet(pkt, pd->frame_size) < 0) {
00127         return AVERROR(ENOMEM);
00128     }
00129 
00130     if ((pa_simple_read(pd->s, pkt->data, pkt->size, &res)) < 0) {
00131         av_log(s, AV_LOG_ERROR, "pa_simple_read failed: %s\n",
00132                pa_strerror(res));
00133         av_free_packet(pkt);
00134         return AVERROR(EIO);
00135     }
00136 
00137     if ((latency = pa_simple_get_latency(pd->s, &res)) == (pa_usec_t) -1) {
00138         av_log(s, AV_LOG_ERROR, "pa_simple_get_latency() failed: %s\n",
00139                pa_strerror(res));
00140         return AVERROR(EIO);
00141     }
00142 
00143     if (pd->pts == AV_NOPTS_VALUE) {
00144         pd->pts = -latency;
00145     }
00146 
00147     pkt->pts = pd->pts;
00148 
00149     pd->pts += pd->frame_duration;
00150 
00151     return 0;
00152 }
00153 
00154 static av_cold int pulse_close(AVFormatContext *s)
00155 {
00156     PulseData *pd = s->priv_data;
00157     pa_simple_free(pd->s);
00158     return 0;
00159 }
00160 
00161 #define OFFSET(a) offsetof(PulseData, a)
00162 #define D AV_OPT_FLAG_DECODING_PARAM
00163 
00164 static const AVOption options[] = {
00165     { "server",        "pulse server name",                              OFFSET(server),        AV_OPT_TYPE_STRING, {.str = NULL},     0, 0, D },
00166     { "name",          "application name",                               OFFSET(name),          AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT},  0, 0, D },
00167     { "stream_name",   "stream description",                             OFFSET(stream_name),   AV_OPT_TYPE_STRING, {.str = "record"}, 0, 0, D },
00168     { "sample_rate",   "sample rate in Hz",                              OFFSET(sample_rate),   AV_OPT_TYPE_INT,    {.dbl = 48000},    1, INT_MAX, D },
00169     { "channels",      "number of audio channels",                       OFFSET(channels),      AV_OPT_TYPE_INT,    {.dbl = 2},        1, INT_MAX, D },
00170     { "frame_size",    "number of bytes per frame",                      OFFSET(frame_size),    AV_OPT_TYPE_INT,    {.dbl = 1024},     1, INT_MAX, D },
00171     { "fragment_size", "buffering size, affects latency and cpu usage",  OFFSET(fragment_size), AV_OPT_TYPE_INT,    {.dbl = -1},      -1, INT_MAX, D },
00172     { NULL },
00173 };
00174 
00175 static const AVClass pulse_demuxer_class = {
00176     .class_name     = "Pulse demuxer",
00177     .item_name      = av_default_item_name,
00178     .option         = options,
00179     .version        = LIBAVUTIL_VERSION_INT,
00180 };
00181 
00182 AVInputFormat ff_pulse_demuxer = {
00183     .name           = "pulse",
00184     .long_name      = NULL_IF_CONFIG_SMALL("Pulse audio input"),
00185     .priv_data_size = sizeof(PulseData),
00186     .read_header    = pulse_read_header,
00187     .read_packet    = pulse_read_packet,
00188     .read_close     = pulse_close,
00189     .flags          = AVFMT_NOFILE,
00190     .priv_class     = &pulse_demuxer_class,
00191 };
Generated on Fri Feb 1 2013 14:34:48 for FFmpeg by doxygen 1.7.1