title: Why is my multi-channel mixer no longer playing in iOS 8?
body: <p>I've written some code to play multi-instrument general MIDI files on iOS.  It works fine in iOS 7, but stopped working on iOS 8.</p>
  
  <p>I've stripped it down to its essence here.  Instead of creating 16 channels for my multi-channel mixer, I just create one sampler node, and map all the tracks to that channel.  It still exhibits the same problem as the multi-sampler version.  None of the Audio Toolbox calls return an error code (they all return 0) in iOS 7 or iOS 8.  The sequence plays through the speakers in iOS 7, on both the simulator and on iPhone/iPad devices.  Run the exact same code on the iOS 8 simulator, or an iPhone/iPad device, and no sound is produced.</p>
  
  <p>If you comment out the call to <code>[self initGraphFromMIDISequence]</code>, it plays on iOS 8 with the default sine-wave sound.</p>
  
  <pre><code>@implementation MyMusicPlayer {
      MusicPlayer _musicPlayer;
      MusicSequence _musicSequence;
      AUGraph _processingGraph;
  }
  
  - (void)playMidi:(NSURL*)midiFileURL {
      NewMusicSequence(&amp;_musicSequence);
      MusicSequenceFileLoad(_musicSequence, CFBridgingRetain(midiFileURL), 0, 0);
  
      NewMusicPlayer(&amp;_musicPlayer);
      MusicPlayerSetSequence(_musicPlayer, _musicSequence);
  
      [self initGraphFromMIDISequence];
  
      MusicPlayerPreroll(_musicPlayer);
      MusicPlayerStart(_musicPlayer);
  }
  
  // Sets up an AUGraph with one channel whose instrument is loaded from a sound bank.
  // Maps all the tracks of the MIDI sequence onto that channel.  Basically this is a
  // way to replace the default sine-wave sound with another (single) instrument.
  - (void)initGraphFromMIDISequence {
      NewAUGraph(&amp;_processingGraph);
  
      // Add one sampler unit to the graph.
      AUNode samplerNode;
      AudioComponentDescription cd = {};
      cd.componentManufacturer = kAudioUnitManufacturer_Apple;
      cd.componentType = kAudioUnitType_MusicDevice;
      cd.componentSubType = kAudioUnitSubType_Sampler;
      AUGraphAddNode(_processingGraph, &amp;cd, &amp;samplerNode);
  
      // Add a Mixer unit node to the graph
      cd.componentType = kAudioUnitType_Mixer;
      cd.componentSubType = kAudioUnitSubType_MultiChannelMixer;
      AUNode mixerNode;
      AUGraphAddNode(_processingGraph, &amp;cd, &amp;mixerNode);
  
      // Add the Output unit node to the graph
      cd.componentType = kAudioUnitType_Output;
      cd.componentSubType = kAudioUnitSubType_RemoteIO; // Output to speakers.
      AUNode ioNode;
      AUGraphAddNode(_processingGraph, &amp;cd, &amp;ioNode);
  
      AUGraphOpen(_processingGraph);
  
      // Obtain the mixer unit instance from its corresponding node, and set the bus count to 1.
      AudioUnit mixerUnit;
      AUGraphNodeInfo(_processingGraph, mixerNode, NULL, &amp;mixerUnit);
      UInt32 const numChannels = 1;
      AudioUnitSetProperty(mixerUnit,
                           kAudioUnitProperty_ElementCount,
                           kAudioUnitScope_Input,
                           0,
                           &amp;numChannels,
                           sizeof(numChannels));
  
      // Connect the sampler node's output 0 to mixer node output 0.
      AUGraphConnectNodeInput(_processingGraph, samplerNode, 0, mixerNode, 0);
  
      // Connect the mixer unit to the output unit.
      AUGraphConnectNodeInput(_processingGraph, mixerNode, 0, ioNode, 0);
  
      // Obtain reference to the audio unit from its node.
      AudioUnit samplerUnit;
      AUGraphNodeInfo(_processingGraph, samplerNode, 0, &amp;samplerUnit);
      MusicSequenceSetAUGraph(_musicSequence, _processingGraph);
  
      // Set the destination for each track to our single sampler node.
      UInt32 trackCount;
      MusicSequenceGetTrackCount(_musicSequence, &amp;trackCount);
      MusicTrack track;
      for (int i = 0; i &lt; trackCount; i++) {
        MusicSequenceGetIndTrack(_musicSequence, i, &amp;track);
        MusicTrackSetDestNode(track, samplerNode);
      }
  
      // You can use either a DLS or an SF2 file bundled with your app; both work in iOS 7.
      //NSString *soundBankPath = [[NSBundle mainBundle] pathForResource:@"GeneralUserv1.44" ofType:@"sf2"];
      NSString *soundBankPath = [[NSBundle mainBundle] pathForResource:@"gs_instruments" ofType:@"dls"];
      NSURL *bankURL = [NSURL fileURLWithPath:soundBankPath];
      AUSamplerBankPresetData bpdata;
      bpdata.bankURL  = (__bridge CFURLRef) bankURL;
      bpdata.bankMSB  = kAUSampler_DefaultMelodicBankMSB;
      bpdata.bankLSB  = kAUSampler_DefaultBankLSB;
      bpdata.presetID = 0;
      UInt8 instrumentNumber = 46;  // pick any GM instrument 0-127
      bpdata.presetID = instrumentNumber;
      AudioUnitSetProperty(samplerUnit,
                           kAUSamplerProperty_LoadPresetFromBank,
                           kAudioUnitScope_Global,
                           0,
                           &amp;bpdata,
                           sizeof(bpdata));
  }
  </code></pre>
  
  <p>I have some code, not included here, which polls to see if the sequence is still playing, by calling <code>MusicPlayerGetTime</code> on the <code>MusicPlayer</code> instance.  In iOS 7, the result of that call each time is the number of seconds that have elapsed since it started playing.  In iOS 8, the call always returns 0, which presumably means the <code>MusicPlayer</code> does not start playing the sequence on the call to <code>MusicPlayerStart</code>.</p>
  
  <p>The code above is highly order-dependent -- you have to make certain calls before others; e.g., opening the graph before calling getInfo on a node, and not loading instruments until you've assigned the tracks to channels.  I've followed all the advice in other StackOverflow threads, and have verified that getting the order correct makes error codes disappear.</p>
  
  <p>Any iOS MIDI experts know what might have changed between iOS 7 and iOS 8 to make this code stop working?</p>