1/*****************************************************
2*
3*  Copyright 2009 Adobe Systems Incorporated.  All Rights Reserved.
4*
5*****************************************************
6*  The contents of this file are subject to the Mozilla Public License
7*  Version 1.1 (the "License"); you may not use this file except in
8*  compliance with the License. You may obtain a copy of the License at
9*  http://www.mozilla.org/MPL/
10*
11*  Software distributed under the License is distributed on an "AS IS"
12*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
13*  License for the specific language governing rights and limitations
14*  under the License.
15*
16*
17*  The Initial Developer of the Original Code is Adobe Systems Incorporated.
18*  Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems
19*  Incorporated. All Rights Reserved.
20*
21*****************************************************/
22package org.osmf.elements.compositeClasses
23{
24	import org.osmf.events.AudioEvent;
25	import org.osmf.traits.AudioTrait;
26	import org.osmf.traits.MediaTraitBase;
27	import org.osmf.traits.MediaTraitType;
28
29	/**
30	 * Implementation of AudioTrait which can be a composite media trait.
31	 *
32	 * For both parallel and serial media elements, a composite audio trait
33	 * keeps all audio properties in sync for the composite element and its
34	 * children.
35	 *
36	 *  @langversion 3.0
37	 *  @playerversion Flash 10
38	 *  @playerversion AIR 1.5
39	 *  @productversion OSMF 1.0
40	 */
41	internal class CompositeAudioTrait extends AudioTrait implements IReusable
42	{
43		/**
44		 * Constructor.
45		 *
46		 * @param traitAggregator The object which is aggregating all instances
47		 * of the AudioTrait within this composite trait.
48		 *
49		 *  @langversion 3.0
50		 *  @playerversion Flash 10
51		 *  @playerversion AIR 1.5
52		 *  @productversion OSMF 1.0
53		 */
54		public function CompositeAudioTrait(traitAggregator:TraitAggregator)
55		{
56			super();
57
58			this.traitAggregator = traitAggregator;
59			traitAggregationHelper = new TraitAggregationHelper
60				( traitType
61				, traitAggregator
62				, processAggregatedChild
63				, processUnaggregatedChild
64				);
65		}
66
67		/**
68		 * @private
69		 */
70		public function attach():void
71		{
72			traitAggregationHelper.attach();
73		}
74
75		/**
76		 * @private
77		 */
78		public function detach():void
79		{
80			traitAggregationHelper.detach();
81		}
82
83		// Overrides
84		//
85
86		override protected function volumeChangeStart(newVolume:Number):void
87		{
88			applyVolumeToChildren(newVolume);
89		}
90
91		override protected function mutedChangeStart(newMuted:Boolean):void
92		{
93			applyMutedToChildren(newMuted);
94		}
95
96		override protected function panChangeStart(newPan:Number):void
97		{
98			applyPanToChildren(newPan);
99		}
100
101		// Internals
102		//
103
104		private function processAggregatedChild(child:MediaTraitBase):void
105		{
106			child.addEventListener(AudioEvent.MUTED_CHANGE,  onMutedChanged, 	false, 0, true);
107			child.addEventListener(AudioEvent.PAN_CHANGE, 	 onPanChanged, 		false, 0, true);
108			child.addEventListener(AudioEvent.VOLUME_CHANGE, onVolumeChanged, 	false, 0, true);
109
110			var audioTrait:AudioTrait = child as AudioTrait;
111
112			if (traitAggregator.getNumTraits(MediaTraitType.AUDIO) == 1)
113			{
114				// The first added child's properties are applied to the
115				// composite trait.
116				pan 	= audioTrait.pan;
117				muted 	= audioTrait.muted;
118				volume  = audioTrait.volume;
119			}
120			else
121			{
122				// All subsequently added children inherit their properties
123				// from the composite trait.
124				audioTrait.pan 		= pan;
125				audioTrait.muted	= muted;
126				audioTrait.volume	= volume;
127			}
128		}
129
130		private function processUnaggregatedChild(child:MediaTraitBase):void
131		{
132			// All we need to do is remove the listeners.  For both parallel
133			// and serial media, unaggregated children have no bearing on
134			// the properties of the composite trait.
135			child.removeEventListener(AudioEvent.MUTED_CHANGE, 	onMutedChanged);
136			child.removeEventListener(AudioEvent.PAN_CHANGE, 	onPanChanged);
137			child.removeEventListener(AudioEvent.VOLUME_CHANGE,	onVolumeChanged);
138		}
139
140		private function onVolumeChanged(event:AudioEvent):void
141		{
142			// Changes from the child propagate to the composite trait.
143			volume = (event.target as AudioTrait).volume;
144		}
145
146		private function onMutedChanged(event:AudioEvent):void
147		{
148			// Changes from the child propagate to the composite trait.
149			muted = (event.target as AudioTrait).muted;
150		}
151
152		private function onPanChanged(event:AudioEvent):void
153		{
154			/// Changes from the child propagate to the composite trait.
155			pan = (event.target as AudioTrait).pan;
156		}
157
158		private function applyVolumeToChildren(newVolume:Number):void
159		{
160			traitAggregator.forEachChildTrait
161				(
162				  function(mediaTrait:MediaTraitBase):void
163				  {
164				     AudioTrait(mediaTrait).volume = newVolume;
165				  }
166				, MediaTraitType.AUDIO
167				);
168		}
169
170		private function applyMutedToChildren(newMuted:Boolean):void
171		{
172			traitAggregator.forEachChildTrait
173				(
174				  function(mediaTrait:MediaTraitBase):void
175				  {
176				     AudioTrait(mediaTrait).muted = newMuted;
177				  }
178				, MediaTraitType.AUDIO
179				);
180		}
181
182		private function applyPanToChildren(newPan:Number):void
183		{
184			traitAggregator.forEachChildTrait
185				(
186				  function(mediaTrait:MediaTraitBase):void
187				  {
188				     AudioTrait(mediaTrait).pan = newPan;
189				  }
190				, MediaTraitType.AUDIO
191				);
192		}
193
194		private var traitAggregator:TraitAggregator;
195		private var traitAggregationHelper:TraitAggregationHelper;
196	}
197}