diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/modules/alsa/alsa-sink.c | 7 | ||||
| -rw-r--r-- | src/pulse/def.h | 17 | ||||
| -rw-r--r-- | src/pulse/stream.c | 10 | ||||
| -rw-r--r-- | src/pulsecore/protocol-native.c | 16 | ||||
| -rw-r--r-- | src/pulsecore/sink-input.c | 44 | ||||
| -rw-r--r-- | src/pulsecore/sink-input.h | 3 | ||||
| -rw-r--r-- | src/pulsecore/sink.c | 18 | ||||
| -rw-r--r-- | src/utils/pacat.c | 7 | 
8 files changed, 117 insertions, 5 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 2e54dbe7..80fdcaa2 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1616,6 +1616,13 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) {              return 0;      } +    /* FIXME: need automatic detection rather than hard-coded path */ +    if (!strcmp(u->mixer_path->name, "iec958-passthrough-output")) { +        u->sink->flags |= PA_SINK_PASSTHROUGH; +    } else { +        u->sink->flags &= ~PA_SINK_PASSTHROUGH; +    } +      if (!u->mixer_path->has_volume)          pa_log_info("Driver does not support hardware volume control, falling back to software volume control.");      else { diff --git a/src/pulse/def.h b/src/pulse/def.h index 82106ef8..80d2a508 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -289,6 +289,12 @@ typedef enum pa_stream_flags {       * device volume. If this is not specified the volume will be       * consider absolute when the sink is in flat volume mode,       * relative otherwise. \since 0.9.20 */ + +    PA_STREAM_PASSTHROUGH = 0x80000U +    /**< Used to tag content that will be rendered by passthrough sinks. +     * The data will be left as is and not reformatted, resampled. +     * \since 0.9.22*/ +  } pa_stream_flags_t;  /** \cond fulldocs */ @@ -316,6 +322,7 @@ typedef enum pa_stream_flags {  #define PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED  #define PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND  #define PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME +#define PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH  /** \endcond */ @@ -729,9 +736,15 @@ typedef enum pa_sink_flags {      /**< This sink is in flat volume mode, i.e. always the maximum of       * the volume of all connected inputs. \since 0.9.15 */ -    PA_SINK_DYNAMIC_LATENCY = 0x0080U +    PA_SINK_DYNAMIC_LATENCY = 0x0080U,      /**< The latency can be adjusted dynamically depending on the       * needs of the connected streams. \since 0.9.15 */ + +    PA_SINK_PASSTHROUGH = 0x0100U +    /**< This sink has support for passthrough mode. The data will be left +     * as is and not reformatted, resampled, mixed. +     * \since 0.9.22*/ +  } pa_sink_flags_t;  /** \cond fulldocs */ @@ -743,6 +756,8 @@ typedef enum pa_sink_flags {  #define PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME  #define PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME  #define PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY +#define PA_SINK_PASSTHROUGH PA_SINK_PASSTHROUGH +  /** \endcond */  /** Sink state. \since 0.9.15 */ diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 36514e0e..87c24ba8 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -1065,7 +1065,9 @@ static int create_stream(                                                PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND|                                                PA_STREAM_START_UNMUTED|                                                PA_STREAM_FAIL_ON_SUSPEND| -                                              PA_STREAM_RELATIVE_VOLUME)), PA_ERR_INVALID); +                                              PA_STREAM_RELATIVE_VOLUME| +                                              PA_STREAM_PASSTHROUGH)), PA_ERR_INVALID); +      PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED);      PA_CHECK_VALIDITY(s->context, s->context->version >= 13 || !(flags & PA_STREAM_PEAK_DETECT), PA_ERR_NOTSUPPORTED); @@ -1206,6 +1208,12 @@ static int create_stream(      } +    if (s->context->version >= 18) { + +        if (s->direction == PA_STREAM_PLAYBACK) +            pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH)); +    } +      pa_pstream_send_tagstruct(s->context->pstream, t);      pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index f3d240b3..adb995f0 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1873,7 +1873,9 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u          dont_inhibit_auto_suspend = FALSE,          muted_set = FALSE,          fail_on_suspend = FALSE, -        relative_volume = FALSE; +        relative_volume = FALSE, +        passthrough = FALSE; +      pa_sink_input_flags_t flags = 0;      pa_proplist *p;      pa_bool_t volume_set = TRUE; @@ -1975,6 +1977,15 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u          }      } +    if (c->version >= 18) { + +        if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) { +            protocol_error(c); +            pa_proplist_free(p); +            return; +        } +    } +      if (!pa_tagstruct_eof(t)) {          protocol_error(c);          pa_proplist_free(p); @@ -2008,7 +2019,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u          (no_move ?  PA_SINK_INPUT_DONT_MOVE : 0) |          (variable_rate ?  PA_SINK_INPUT_VARIABLE_RATE : 0) |          (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | -        (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0); +        (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) | +        (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);      /* Only since protocol version 15 there's a seperate muted_set       * flag. For older versions we synthesize it here */ diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 395110b7..190e2d01 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -55,6 +55,39 @@ static void sink_input_volume_ramping(pa_sink_input* i, pa_memchunk* chunk);  static void sink_input_rewind_ramp_info(pa_sink_input *i, size_t nbytes);  static void sink_input_release_envelope(pa_sink_input *i); +static int check_passthrough_connection(pa_sink_input_flags_t flags, pa_sink *dest) { + +    if (dest->flags & PA_SINK_PASSTHROUGH) { + +        if (pa_idxset_size(dest->inputs) > 0) { + +            pa_sink_input *alt_i; +            uint32_t idx; + +            alt_i = pa_idxset_first(dest->inputs, &idx); + +            /* only need to check the first input is not PASSTHROUGH */ +            if (alt_i->flags & PA_SINK_INPUT_PASSTHROUGH) { +                pa_log_warn("Sink is already connected to PASSTHROUGH input"); +                return -PA_ERR_BUSY; +            } + +            /* Current inputs are PCM, check new input is not PASSTHROUGH */ +            if (flags & PA_SINK_INPUT_PASSTHROUGH) { +                pa_log_warn("Sink is already connected, cannot accept new PASSTHROUGH INPUT"); +                return -PA_ERR_BUSY; +            } +        } + +    } else { +         if (flags & PA_SINK_INPUT_PASSTHROUGH) { +             pa_log_warn("Cannot connect PASSTHROUGH sink input to sink without PASSTHROUGH capabilities"); +             return -PA_ERR_INVALID; +         } +    } +    return PA_OK; +} +  pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {      pa_assert(data); @@ -183,6 +216,9 @@ int pa_sink_input_new(      pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE);      pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED), -PA_ERR_INVALID); +    r = check_passthrough_connection(data->flags, data->sink); +    pa_return_val_if_fail(r == PA_OK, r); +      if (!data->sample_spec_is_set)          data->sample_spec = data->sink->sample_spec; @@ -1020,6 +1056,11 @@ static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) {  /* Called from main context */  void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) { + +    /* Do not allow for volume changes for non-audio types */ +    if (i->flags & PA_SINK_INPUT_PASSTHROUGH) +        return; +      /* test ramping -> return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 2000 * PA_USEC_PER_MSEC); */      return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 0);  } @@ -1162,6 +1203,9 @@ pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {          return FALSE;      } +    if (check_passthrough_connection(i->flags, dest) < 0) +        return FALSE; +      if (i->may_move_to)          if (!i->may_move_to(i, dest))              return FALSE; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 56ac3d60..4491d8a3 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -61,7 +61,8 @@ typedef enum pa_sink_input_flags {      PA_SINK_INPUT_FIX_CHANNELS = 128,      PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256,      PA_SINK_INPUT_NO_CREATE_ON_SUSPEND = 512, -    PA_SINK_INPUT_KILL_ON_SUSPEND = 1024 +    PA_SINK_INPUT_KILL_ON_SUSPEND = 1024, +    PA_SINK_INPUT_PASSTHROUGH = 2048  } pa_sink_input_flags_t;  struct pa_sink_input { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index d69f0388..b68ad3aa 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1393,6 +1393,24 @@ void pa_sink_set_volume(      pa_assert(volume || (s->flags & PA_SINK_FLAT_VOLUME));      pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec)); +    /* make sure we don't change the volume when a PASSTHROUGH input is connected */ +    if (s->flags & PA_SINK_PASSTHROUGH) { +        pa_sink_input *alt_i; +        uint32_t idx; + +        /* one and only one PASSTHROUGH input can possibly be connected */ +        if (pa_idxset_size(s->inputs) == 1) { + +            alt_i = pa_idxset_first(s->inputs, &idx); + +            if (alt_i->flags & PA_SINK_INPUT_PASSTHROUGH) { +                /* FIXME: Need to notify client that volume control is disabled */ +                pa_log_warn("Cannot change volume, Sink is connected to PASSTHROUGH input"); +                return; +            } +        } +    } +      /* As a special exception we accept mono volumes on all sinks --       * even on those with more complex channel maps */ diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 6cbff2e6..79936fd7 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -659,6 +659,7 @@ static void help(const char *argv0) {               "      --process-time-msec=MSEC          Request the specified process time per request in msec.\n"               "      --property=PROPERTY=VALUE         Set the specified property to the specified value.\n"               "      --raw                             Record/play raw PCM data.\n" +             "      --passthrough                     passthrough data \n"               "      --file-format[=FFORMAT]           Record/play formatted PCM data.\n"               "      --list-file-formats               List available file formats.\n")             , argv0); @@ -680,6 +681,7 @@ enum {      ARG_LATENCY,      ARG_PROCESS_TIME,      ARG_RAW, +    ARG_PASSTHROUGH,      ARG_PROPERTY,      ARG_FILE_FORMAT,      ARG_LIST_FILE_FORMATS, @@ -718,6 +720,7 @@ int main(int argc, char *argv[]) {          {"process-time", 1, NULL, ARG_PROCESS_TIME},          {"property",     1, NULL, ARG_PROPERTY},          {"raw",          0, NULL, ARG_RAW}, +        {"passthrough",  0, NULL, ARG_PASSTHROUGH},          {"file-format",  2, NULL, ARG_FILE_FORMAT},          {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},          {"latency-msec", 1, NULL, ARG_LATENCY_MSEC}, @@ -914,6 +917,10 @@ int main(int argc, char *argv[]) {                  raw = TRUE;                  break; +            case ARG_PASSTHROUGH: +                flags |= PA_STREAM_PASSTHROUGH; +                break; +              case ARG_FILE_FORMAT:                  raw = FALSE;  | 
