Index: src/wp-includes/js/mce-view.js
===================================================================
--- src/wp-includes/js/mce-view.js	(revision 28181)
+++ src/wp-includes/js/mce-view.js	(working copy)
@@ -451,10 +451,6 @@
 				firefox = this.ua.is( 'ff' ),
 				className = '.wp-' +  this.shortcode.tag + '-shortcode';
 
-			if ( this.player ) {
-				this.unsetPlayer();
-			}
-
 			media = $( node ).find( className );
 
 			if ( ! this.isCompatible( media ) ) {
@@ -495,12 +491,7 @@
 		},
 
 		unbind: function() {
-			var self = this;
-			this.pauseAllPlayers();
-			_.each( this.players, function (player) {
-				self.removePlayer( player );
-			} );
-			this.players = [];
+			this.unsetPlayers();
 		}
 	});
 	_.extend( wp.mce.media.View.prototype, wp.media.mixin );
@@ -547,22 +538,10 @@
 		template:  media.template('editor-playlist'),
 
 		initialize: function( options ) {
+			this.players = [];
 			this.data = {};
 			this.attachments = [];
 			this.shortcode = options.shortcode;
-			_.bindAll( this, 'setPlayer' );
-			$(this).on('ready', this.setNode);
-		},
-
-		/**
-		 * Set the element context for the view, and then fetch the playlist's
-		 *   associated attachments.
-		 *
-		 * @param {Event} e
-		 * @param {HTMLElement} node
-		 */
-		setNode: function(e, node) {
-			this.node = node;
 			this.fetch();
 		},
 
@@ -571,7 +550,7 @@
 		 */
 		fetch: function() {
 			this.attachments = wp.media.playlist.attachments( this.shortcode );
-			this.attachments.more().done( this.setPlayer );
+			this.dfd = this.attachments.more().done( _.bind( this.render, this ) );
 		},
 
 		/**
@@ -582,36 +561,33 @@
 		 * @global WPPlaylistView
 		 * @global tinymce.editors
 		 */
-		setPlayer: function() {
-			var p,
-				html = this.getHtml(),
-				t = this.encodedText,
-				self = this;
+		render: function() {
+			var html = this.getHtml(), self = this;
 
-			this.unsetPlayer();
+			this.unsetPlayers();
 
 			_.each( tinymce.editors, function( editor ) {
 				var doc;
 				if ( editor.plugins.wpview ) {
 					doc = editor.getDoc();
-					$( doc ).find( '[data-wpview-text="' + t + '"]' ).each(function(i, elem) {
+					$( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each(function (i, elem) {
 						var node = $( elem );
-						node.html( html );
-						self.node = elem;
+
+						// The <ins> is used to mark the end of the wrapper div. Needed when comparing
+						// the content as string for preventing extra undo levels.
+						node.html( html ).append( '<ins data-wpview-end="1"></ins>' );
+
+						if ( ! self.data.tracks ) {
+							return;
+						}
+
+						self.players.push( new WPPlaylistView({
+							el: $( elem ).find( '.wp-playlist' ).get(0),
+							metadata: self.data
+						}).player );
 					});
 				}
 			}, this );
-
-			if ( ! this.data.tracks ) {
-				return;
-			}
-
-			p = new WPPlaylistView({
-				el: $( self.node ).find( '.wp-playlist' ).get(0),
-				metadata: this.data
-			});
-
-			this.player = p.player;
 		},
 
 		/**
Index: src/wp-includes/js/media-audiovideo.js
===================================================================
--- src/wp-includes/js/media-audiovideo.js	(revision 28181)
+++ src/wp-includes/js/media-audiovideo.js	(working copy)
@@ -162,11 +162,13 @@
 		 *
 		 *  Examples: modal closes, shortcode properties are removed, etc.
 		 */
-		unsetPlayer : function() {
-			if ( this.player ) {
+		unsetPlayers : function() {
+			if ( this.players && this.players.length ) {
 				wp.media.mixin.pauseAllPlayers();
-				wp.media.mixin.removePlayer( this.player );
-				this.player = false;
+				_.each( this.players, function (player) {
+					wp.media.mixin.removePlayer( player );
+				} );
+				this.players = [];
 			}
 		}
 	};
@@ -706,9 +708,9 @@
 		initialize: function() {
 			_.bindAll(this, 'success');
 
-			this.listenTo( this.controller, 'close', media.mixin.unsetPlayer );
+			this.listenTo( this.controller, 'close', media.mixin.unsetPlayers );
 			this.on( 'ready', this.setPlayer );
-			this.on( 'media:setting:remove', media.mixin.unsetPlayer, this );
+			this.on( 'media:setting:remove', media.mixin.unsetPlayers, this );
 			this.on( 'media:setting:remove', this.render );
 			this.on( 'media:setting:remove', this.setPlayer );
 			this.events = _.extend( this.events, {
@@ -764,8 +766,8 @@
 		 * @global MediaElementPlayer
 		 */
 		setPlayer : function() {
-			if ( ! this.player && this.media ) {
-				this.player = new MediaElementPlayer( this.media, this.settings );
+			if ( ! this.players.length && this.media ) {
+				this.players.push( new MediaElementPlayer( this.media, this.settings ) );
 			}
 		},
 
