LCOV - code coverage report
Current view: top level - libavdevice - alsa.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 198 0.0 %
Date: 2017-10-24 00:14:43 Functions: 0 19 0.0 %

          Line data    Source code
       1             : /*
       2             :  * ALSA input and output
       3             :  * Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
       4             :  * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : /**
      24             :  * @file
      25             :  * ALSA input and output: common code
      26             :  * @author Luca Abeni ( lucabe72 email it )
      27             :  * @author Benoit Fouet ( benoit fouet free fr )
      28             :  * @author Nicolas George ( nicolas george normalesup org )
      29             :  */
      30             : 
      31             : #include <alsa/asoundlib.h>
      32             : #include "avdevice.h"
      33             : #include "libavutil/avassert.h"
      34             : #include "libavutil/channel_layout.h"
      35             : 
      36             : #include "alsa.h"
      37             : 
      38           0 : static av_cold snd_pcm_format_t codec_id_to_pcm_format(int codec_id)
      39             : {
      40           0 :     switch(codec_id) {
      41           0 :         case AV_CODEC_ID_PCM_F64LE: return SND_PCM_FORMAT_FLOAT64_LE;
      42           0 :         case AV_CODEC_ID_PCM_F64BE: return SND_PCM_FORMAT_FLOAT64_BE;
      43           0 :         case AV_CODEC_ID_PCM_F32LE: return SND_PCM_FORMAT_FLOAT_LE;
      44           0 :         case AV_CODEC_ID_PCM_F32BE: return SND_PCM_FORMAT_FLOAT_BE;
      45           0 :         case AV_CODEC_ID_PCM_S32LE: return SND_PCM_FORMAT_S32_LE;
      46           0 :         case AV_CODEC_ID_PCM_S32BE: return SND_PCM_FORMAT_S32_BE;
      47           0 :         case AV_CODEC_ID_PCM_U32LE: return SND_PCM_FORMAT_U32_LE;
      48           0 :         case AV_CODEC_ID_PCM_U32BE: return SND_PCM_FORMAT_U32_BE;
      49           0 :         case AV_CODEC_ID_PCM_S24LE: return SND_PCM_FORMAT_S24_3LE;
      50           0 :         case AV_CODEC_ID_PCM_S24BE: return SND_PCM_FORMAT_S24_3BE;
      51           0 :         case AV_CODEC_ID_PCM_U24LE: return SND_PCM_FORMAT_U24_3LE;
      52           0 :         case AV_CODEC_ID_PCM_U24BE: return SND_PCM_FORMAT_U24_3BE;
      53           0 :         case AV_CODEC_ID_PCM_S16LE: return SND_PCM_FORMAT_S16_LE;
      54           0 :         case AV_CODEC_ID_PCM_S16BE: return SND_PCM_FORMAT_S16_BE;
      55           0 :         case AV_CODEC_ID_PCM_U16LE: return SND_PCM_FORMAT_U16_LE;
      56           0 :         case AV_CODEC_ID_PCM_U16BE: return SND_PCM_FORMAT_U16_BE;
      57           0 :         case AV_CODEC_ID_PCM_S8:    return SND_PCM_FORMAT_S8;
      58           0 :         case AV_CODEC_ID_PCM_U8:    return SND_PCM_FORMAT_U8;
      59           0 :         case AV_CODEC_ID_PCM_MULAW: return SND_PCM_FORMAT_MU_LAW;
      60           0 :         case AV_CODEC_ID_PCM_ALAW:  return SND_PCM_FORMAT_A_LAW;
      61           0 :         default:                 return SND_PCM_FORMAT_UNKNOWN;
      62             :     }
      63             : }
      64             : 
      65             : #define MAKE_REORDER_FUNC(NAME, TYPE, CHANNELS, LAYOUT, MAP)                \
      66             : static void alsa_reorder_ ## NAME ## _ ## LAYOUT(const void *in_v,          \
      67             :                                                  void *out_v,               \
      68             :                                                  int n)                     \
      69             : {                                                                           \
      70             :     const TYPE *in = in_v;                                                  \
      71             :     TYPE      *out = out_v;                                                 \
      72             :                                                                             \
      73             :     while (n-- > 0) {                                                       \
      74             :         MAP                                                                 \
      75             :         in  += CHANNELS;                                                    \
      76             :         out += CHANNELS;                                                    \
      77             :     }                                                                       \
      78             : }
      79             : 
      80             : #define MAKE_REORDER_FUNCS(CHANNELS, LAYOUT, MAP) \
      81             :     MAKE_REORDER_FUNC(int8,  int8_t,  CHANNELS, LAYOUT, MAP) \
      82             :     MAKE_REORDER_FUNC(int16, int16_t, CHANNELS, LAYOUT, MAP) \
      83             :     MAKE_REORDER_FUNC(int32, int32_t, CHANNELS, LAYOUT, MAP) \
      84             :     MAKE_REORDER_FUNC(f32,   float,   CHANNELS, LAYOUT, MAP)
      85             : 
      86           0 : MAKE_REORDER_FUNCS(5, out_50, \
      87             :         out[0] = in[0]; \
      88             :         out[1] = in[1]; \
      89             :         out[2] = in[3]; \
      90             :         out[3] = in[4]; \
      91             :         out[4] = in[2]; \
      92             :         )
      93             : 
      94           0 : MAKE_REORDER_FUNCS(6, out_51, \
      95             :         out[0] = in[0]; \
      96             :         out[1] = in[1]; \
      97             :         out[2] = in[4]; \
      98             :         out[3] = in[5]; \
      99             :         out[4] = in[2]; \
     100             :         out[5] = in[3]; \
     101             :         )
     102             : 
     103           0 : MAKE_REORDER_FUNCS(8, out_71, \
     104             :         out[0] = in[0]; \
     105             :         out[1] = in[1]; \
     106             :         out[2] = in[4]; \
     107             :         out[3] = in[5]; \
     108             :         out[4] = in[2]; \
     109             :         out[5] = in[3]; \
     110             :         out[6] = in[6]; \
     111             :         out[7] = in[7]; \
     112             :         )
     113             : 
     114             : #define FORMAT_I8  0
     115             : #define FORMAT_I16 1
     116             : #define FORMAT_I32 2
     117             : #define FORMAT_F32 3
     118             : 
     119             : #define PICK_REORDER(layout)\
     120             : switch(format) {\
     121             :     case FORMAT_I8:  s->reorder_func = alsa_reorder_int8_out_ ##layout;  break;\
     122             :     case FORMAT_I16: s->reorder_func = alsa_reorder_int16_out_ ##layout; break;\
     123             :     case FORMAT_I32: s->reorder_func = alsa_reorder_int32_out_ ##layout; break;\
     124             :     case FORMAT_F32: s->reorder_func = alsa_reorder_f32_out_ ##layout;   break;\
     125             : }
     126             : 
     127           0 : static av_cold int find_reorder_func(AlsaData *s, int codec_id, uint64_t layout, int out)
     128             : {
     129             :     int format;
     130             : 
     131             :     /* reordering input is not currently supported */
     132           0 :     if (!out)
     133           0 :         return AVERROR(ENOSYS);
     134             : 
     135             :     /* reordering is not needed for QUAD or 2_2 layout */
     136           0 :     if (layout == AV_CH_LAYOUT_QUAD || layout == AV_CH_LAYOUT_2_2)
     137           0 :         return 0;
     138             : 
     139           0 :     switch (codec_id) {
     140           0 :     case AV_CODEC_ID_PCM_S8:
     141             :     case AV_CODEC_ID_PCM_U8:
     142             :     case AV_CODEC_ID_PCM_ALAW:
     143           0 :     case AV_CODEC_ID_PCM_MULAW: format = FORMAT_I8;  break;
     144           0 :     case AV_CODEC_ID_PCM_S16LE:
     145             :     case AV_CODEC_ID_PCM_S16BE:
     146             :     case AV_CODEC_ID_PCM_U16LE:
     147           0 :     case AV_CODEC_ID_PCM_U16BE: format = FORMAT_I16; break;
     148           0 :     case AV_CODEC_ID_PCM_S32LE:
     149             :     case AV_CODEC_ID_PCM_S32BE:
     150             :     case AV_CODEC_ID_PCM_U32LE:
     151           0 :     case AV_CODEC_ID_PCM_U32BE: format = FORMAT_I32; break;
     152           0 :     case AV_CODEC_ID_PCM_F32LE:
     153           0 :     case AV_CODEC_ID_PCM_F32BE: format = FORMAT_F32; break;
     154           0 :     default:                 return AVERROR(ENOSYS);
     155             :     }
     156             : 
     157           0 :     if      (layout == AV_CH_LAYOUT_5POINT0_BACK || layout == AV_CH_LAYOUT_5POINT0)
     158           0 :         PICK_REORDER(50)
     159           0 :     else if (layout == AV_CH_LAYOUT_5POINT1_BACK || layout == AV_CH_LAYOUT_5POINT1)
     160           0 :         PICK_REORDER(51)
     161           0 :     else if (layout == AV_CH_LAYOUT_7POINT1)
     162           0 :         PICK_REORDER(71)
     163             : 
     164           0 :     return s->reorder_func ? 0 : AVERROR(ENOSYS);
     165             : }
     166             : 
     167           0 : av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
     168             :                          unsigned int *sample_rate,
     169             :                          int channels, enum AVCodecID *codec_id)
     170             : {
     171           0 :     AlsaData *s = ctx->priv_data;
     172             :     const char *audio_device;
     173           0 :     int res, flags = 0;
     174             :     snd_pcm_format_t format;
     175             :     snd_pcm_t *h;
     176             :     snd_pcm_hw_params_t *hw_params;
     177             :     snd_pcm_uframes_t buffer_size, period_size;
     178           0 :     uint64_t layout = ctx->streams[0]->codecpar->channel_layout;
     179             : 
     180           0 :     if (ctx->filename[0] == 0) audio_device = "default";
     181           0 :     else                       audio_device = ctx->filename;
     182             : 
     183           0 :     if (*codec_id == AV_CODEC_ID_NONE)
     184           0 :         *codec_id = DEFAULT_CODEC_ID;
     185           0 :     format = codec_id_to_pcm_format(*codec_id);
     186           0 :     if (format == SND_PCM_FORMAT_UNKNOWN) {
     187           0 :         av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id);
     188           0 :         return AVERROR(ENOSYS);
     189             :     }
     190           0 :     s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels;
     191             : 
     192           0 :     if (ctx->flags & AVFMT_FLAG_NONBLOCK) {
     193           0 :         flags = SND_PCM_NONBLOCK;
     194             :     }
     195           0 :     res = snd_pcm_open(&h, audio_device, mode, flags);
     196           0 :     if (res < 0) {
     197           0 :         av_log(ctx, AV_LOG_ERROR, "cannot open audio device %s (%s)\n",
     198             :                audio_device, snd_strerror(res));
     199           0 :         return AVERROR(EIO);
     200             :     }
     201             : 
     202           0 :     res = snd_pcm_hw_params_malloc(&hw_params);
     203           0 :     if (res < 0) {
     204           0 :         av_log(ctx, AV_LOG_ERROR, "cannot allocate hardware parameter structure (%s)\n",
     205             :                snd_strerror(res));
     206           0 :         goto fail1;
     207             :     }
     208             : 
     209           0 :     res = snd_pcm_hw_params_any(h, hw_params);
     210           0 :     if (res < 0) {
     211           0 :         av_log(ctx, AV_LOG_ERROR, "cannot initialize hardware parameter structure (%s)\n",
     212             :                snd_strerror(res));
     213           0 :         goto fail;
     214             :     }
     215             : 
     216           0 :     res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
     217           0 :     if (res < 0) {
     218           0 :         av_log(ctx, AV_LOG_ERROR, "cannot set access type (%s)\n",
     219             :                snd_strerror(res));
     220           0 :         goto fail;
     221             :     }
     222             : 
     223           0 :     res = snd_pcm_hw_params_set_format(h, hw_params, format);
     224           0 :     if (res < 0) {
     225           0 :         av_log(ctx, AV_LOG_ERROR, "cannot set sample format 0x%04x %d (%s)\n",
     226             :                *codec_id, format, snd_strerror(res));
     227           0 :         goto fail;
     228             :     }
     229             : 
     230           0 :     res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0);
     231           0 :     if (res < 0) {
     232           0 :         av_log(ctx, AV_LOG_ERROR, "cannot set sample rate (%s)\n",
     233             :                snd_strerror(res));
     234           0 :         goto fail;
     235             :     }
     236             : 
     237           0 :     res = snd_pcm_hw_params_set_channels(h, hw_params, channels);
     238           0 :     if (res < 0) {
     239           0 :         av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n",
     240             :                channels, snd_strerror(res));
     241           0 :         goto fail;
     242             :     }
     243             : 
     244           0 :     snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size);
     245           0 :     buffer_size = FFMIN(buffer_size, ALSA_BUFFER_SIZE_MAX);
     246             :     /* TODO: maybe use ctx->max_picture_buffer somehow */
     247           0 :     res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size);
     248           0 :     if (res < 0) {
     249           0 :         av_log(ctx, AV_LOG_ERROR, "cannot set ALSA buffer size (%s)\n",
     250             :                snd_strerror(res));
     251           0 :         goto fail;
     252             :     }
     253             : 
     254           0 :     snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL);
     255           0 :     if (!period_size)
     256           0 :         period_size = buffer_size / 4;
     257           0 :     res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL);
     258           0 :     if (res < 0) {
     259           0 :         av_log(ctx, AV_LOG_ERROR, "cannot set ALSA period size (%s)\n",
     260             :                snd_strerror(res));
     261           0 :         goto fail;
     262             :     }
     263           0 :     s->period_size = period_size;
     264             : 
     265           0 :     res = snd_pcm_hw_params(h, hw_params);
     266           0 :     if (res < 0) {
     267           0 :         av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n",
     268             :                snd_strerror(res));
     269           0 :         goto fail;
     270             :     }
     271             : 
     272           0 :     snd_pcm_hw_params_free(hw_params);
     273             : 
     274           0 :     if (channels > 2 && layout) {
     275           0 :         if (find_reorder_func(s, *codec_id, layout, mode == SND_PCM_STREAM_PLAYBACK) < 0) {
     276             :             char name[128];
     277           0 :             av_get_channel_layout_string(name, sizeof(name), channels, layout);
     278           0 :             av_log(ctx, AV_LOG_WARNING, "ALSA channel layout unknown or unimplemented for %s %s.\n",
     279             :                    name, mode == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture");
     280             :         }
     281           0 :         if (s->reorder_func) {
     282           0 :             s->reorder_buf_size = buffer_size;
     283           0 :             s->reorder_buf = av_malloc_array(s->reorder_buf_size, s->frame_size);
     284           0 :             if (!s->reorder_buf)
     285           0 :                 goto fail1;
     286             :         }
     287             :     }
     288             : 
     289           0 :     s->h = h;
     290           0 :     return 0;
     291             : 
     292           0 : fail:
     293           0 :     snd_pcm_hw_params_free(hw_params);
     294           0 : fail1:
     295           0 :     snd_pcm_close(h);
     296           0 :     return AVERROR(EIO);
     297             : }
     298             : 
     299           0 : av_cold int ff_alsa_close(AVFormatContext *s1)
     300             : {
     301           0 :     AlsaData *s = s1->priv_data;
     302             : 
     303           0 :     snd_pcm_nonblock(s->h, 0);
     304           0 :     snd_pcm_drain(s->h);
     305           0 :     av_freep(&s->reorder_buf);
     306             :     if (CONFIG_ALSA_INDEV)
     307           0 :         ff_timefilter_destroy(s->timefilter);
     308           0 :     snd_pcm_close(s->h);
     309           0 :     return 0;
     310             : }
     311             : 
     312           0 : int ff_alsa_xrun_recover(AVFormatContext *s1, int err)
     313             : {
     314           0 :     AlsaData *s = s1->priv_data;
     315           0 :     snd_pcm_t *handle = s->h;
     316             : 
     317           0 :     av_log(s1, AV_LOG_WARNING, "ALSA buffer xrun.\n");
     318           0 :     if (err == -EPIPE) {
     319           0 :         err = snd_pcm_prepare(handle);
     320           0 :         if (err < 0) {
     321           0 :             av_log(s1, AV_LOG_ERROR, "cannot recover from underrun (snd_pcm_prepare failed: %s)\n", snd_strerror(err));
     322             : 
     323           0 :             return AVERROR(EIO);
     324             :         }
     325           0 :     } else if (err == -ESTRPIPE) {
     326           0 :         av_log(s1, AV_LOG_ERROR, "-ESTRPIPE... Unsupported!\n");
     327             : 
     328           0 :         return -1;
     329             :     }
     330           0 :     return err;
     331             : }
     332             : 
     333           0 : int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size)
     334             : {
     335           0 :     int size = s->reorder_buf_size;
     336             :     void *r;
     337             : 
     338           0 :     av_assert0(size != 0);
     339           0 :     while (size < min_size)
     340           0 :         size *= 2;
     341           0 :     r = av_realloc_array(s->reorder_buf, size, s->frame_size);
     342           0 :     if (!r)
     343           0 :         return AVERROR(ENOMEM);
     344           0 :     s->reorder_buf = r;
     345           0 :     s->reorder_buf_size = size;
     346           0 :     return 0;
     347             : }
     348             : 
     349             : /* ported from alsa-utils/aplay.c */
     350           0 : int ff_alsa_get_device_list(AVDeviceInfoList *device_list, snd_pcm_stream_t stream_type)
     351             : {
     352           0 :     int ret = 0;
     353             :     void **hints, **n;
     354           0 :     char *name = NULL, *descr = NULL, *io = NULL, *tmp;
     355           0 :     AVDeviceInfo *new_device = NULL;
     356           0 :     const char *filter = stream_type == SND_PCM_STREAM_PLAYBACK ? "Output" : "Input";
     357             : 
     358           0 :     if (snd_device_name_hint(-1, "pcm", &hints) < 0)
     359           0 :         return AVERROR_EXTERNAL;
     360           0 :     n = hints;
     361           0 :     while (*n && !ret) {
     362           0 :         name = snd_device_name_get_hint(*n, "NAME");
     363           0 :         descr = snd_device_name_get_hint(*n, "DESC");
     364           0 :         io = snd_device_name_get_hint(*n, "IOID");
     365           0 :         if (!io || !strcmp(io, filter)) {
     366           0 :             new_device = av_mallocz(sizeof(AVDeviceInfo));
     367           0 :             if (!new_device) {
     368           0 :                 ret = AVERROR(ENOMEM);
     369           0 :                 goto fail;
     370             :             }
     371           0 :             new_device->device_name = av_strdup(name);
     372           0 :             if ((tmp = strrchr(descr, '\n')) && tmp[1])
     373           0 :                 new_device->device_description = av_strdup(&tmp[1]);
     374             :             else
     375           0 :                 new_device->device_description = av_strdup(descr);
     376           0 :             if (!new_device->device_description || !new_device->device_name) {
     377           0 :                 ret = AVERROR(ENOMEM);
     378           0 :                 goto fail;
     379             :             }
     380           0 :             if ((ret = av_dynarray_add_nofree(&device_list->devices,
     381             :                                               &device_list->nb_devices, new_device)) < 0) {
     382           0 :                 goto fail;
     383             :             }
     384           0 :             if (!strcmp(new_device->device_name, "default"))
     385           0 :                 device_list->default_device = device_list->nb_devices - 1;
     386           0 :             new_device = NULL;
     387             :         }
     388           0 :       fail:
     389           0 :         free(io);
     390           0 :         free(name);
     391           0 :         free(descr);
     392           0 :         n++;
     393             :     }
     394           0 :     if (new_device) {
     395           0 :         av_free(new_device->device_description);
     396           0 :         av_free(new_device->device_name);
     397           0 :         av_free(new_device);
     398             :     }
     399           0 :     snd_device_name_free_hint(hints);
     400           0 :     return ret;
     401             : }

Generated by: LCOV version 1.13