title: How to set channel positions/a channel mask in gstreamer?
body: <p>I'm trying to get 28 channels out of a <code>jackaudiosrc</code> but as soon
  as I connect, say, a <code>deinterleave</code> element, the source will fall back to
  the 2-channel setup that works without any channel mask. My attempts at
  setting a channel mask have been futile.</p>
  
  <p>Here's what happens:</p>
  
  <pre><code>potential caps: audio/x-raw-float, endianness=(int)1234, width=(int)32, rate=(int)48000, channels=(int)[ 1, 28 ]
  filter caps: audio/x-raw-float, channels=(int)28, channel-positions=(GstAudioChannelPosition)&lt; GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE, GST_AUDIO_CHANNEL_POSITION_NONE &gt;
  actual caps: audio/x-raw-float, endianness=(int)1234, width=(int)32, rate=(int)48000, channels=(int)2, channel-positions=(GstAudioChannelPosition)&lt; GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT &gt;
  </code></pre>
  
  <p>And here's the Python code that produces that output:</p>
  
  <pre class="lang-python prettyprint-override"><code>import pygst
  pygst.require("0.10")
  import gst
  import gobject
  import gst.audio
  
  gobject.threads_init()
  pipeline = gst.Pipeline("mypipeline")
  src = gst.element_factory_make("jackaudiosrc", "jacksrc")
  pipeline.add(src)
  srcpad = src.get_pad("src")
  pipeline.set_state(gst.STATE_PLAYING)
  print 'potential caps:',srcpad.get_caps()
  sink = gst.element_factory_make("fakesink", "sink")
  pipeline.add(sink)
  filtercaps = gst.caps_from_string("audio/x-raw-float,channels=28")
  filtercaps[0].set_value("channel-positions", tuple([gst.audio.AUDIO_CHANNEL_POSITION_NONE]*28))
  print "filter caps:",filtercaps
  src.link_filtered(sink, filtercaps)
  pipeline.set_state(gst.STATE_PLAYING)
  print 'actual caps:',srcpad.get_negotiated_caps()
  #gst.DEBUG_BIN_TO_DOT_FILE_WITH_TS(pipeline, gst.DEBUG_GRAPH_SHOW_ALL, 'caps')
  </code></pre>
  
  <p>I also tried to set the caps of the output directly instead of using a
  filter but that didn't do anything either.</p>
  
  <p>Here's the output of that last bin-to-dot-file line (click to enlarge).</p>
  
  <p><a href="https://i.stack.imgur.com/Xsdzn.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Xsdzn.png" alt="dot file output for 0.10"></a></p>
  
  <p>Here's a <code>gst-launch</code> line that works without an actual multichannel audio setup but does <em>not</em> actually reproduce the error, I believe because the <code>interleave</code> element sets the NONE caps correctly by default while the <code>jackaudiosrc</code> doesn't. Maybe it still helps people to play around with this issue who can't reproduce it themselves because of technical restrictions. Credit to <a href="http://tristanswork.blogspot.de/2008/08/multichannel-audio-with-gstreamer.html" rel="nofollow noreferrer">http://tristanswork.blogspot.de/2008/08/multichannel-audio-with-gstreamer.html</a> for the original launch line that I adapted.</p>
  
  <pre><code>gst-launch-0.10 interleave name=i ! audioconvert ! audioresample ! queue ! deinterleave name=o audiotestsrc ! audioconvert ! queue ! i. audiotestsrc ! audioconvert ! queue ! i. audiotestsrc ! audioconvert ! queue ! i. o. ! queue ! fakesink dump=true o. ! queue ! fakesink dump=true o. ! queue ! fakesink dump=true
  </code></pre>
  
  <p><strong>Edit:</strong> I now tried to do the same thing in GStreamer 1.x. The <code>tuple</code> data type is no longer accepted so here's what I came up with after having a look at others wrote channel positions directly to the <code>get_caps_from_string</code> function.</p>
  
  <pre><code>from gi.repository import GObject, Gst, GstAudio
  GObject.threads_init()
  Gst.init(None)
  pipeline = Gst.Pipeline("mypipeline")
  src = Gst.ElementFactory.make("jackaudiosrc", "jacksrc")
  pipeline.add(src)
  srcpad = src.get_static_pad("src")
  pipeline.set_state(Gst.State.PLAYING)
  print 'potential caps:', srcpad.query_caps()
  sink = Gst.ElementFactory.make("fakesink", "sink")
  pipeline.add(sink)
  filtercaps = Gst.caps_from_string("audio/x-raw, channels=(int)28, channel-positions=(int)&lt; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 &gt;")
  print "filter caps:", filtercaps
  src.link_filtered(sink, filtercaps)
  pipeline.set_state(Gst.State.PLAYING)
  print 'actual caps:', srcpad.get_current_caps()
  Gst.debug_bin_to_dot_file_with_ts(pipeline, Gst.DebugGraphDetails.ALL, 'caps')
  </code></pre>
  
  <p>The output both in text form and the graph are shockingly similar:</p>
  
  <pre><code>potential caps: audio/x-raw, format=(string)F32LE, layout=(string)interleaved, rate=(int)48000, channels=(int)[ 1, 28 ]
  filter caps: audio/x-raw, channels=(int)28, channel-positions=(int)&lt; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 &gt;
  actual caps: audio/x-raw, format=(string)F32LE, layout=(string)interleaved, rate=(int)48000, channels=(int)2
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/dRMte.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/dRMte.png" alt="dot file output for 1.4"></a></p>