sbGStreamerAudioProcessor.h
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2010 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
25 #ifndef _SB_GSTREAMER_AUDIO_PROCESSOR_H_
26 #define _SB_GSTREAMER_AUDIO_PROCESSOR_H_
27 
28 #include <nsCOMPtr.h>
29 #include <nsCOMArray.h>
30 
31 #include <nsIClassInfo.h>
32 
33 #include <gst/gst.h>
34 #include <gst/app/gstappsink.h>
35 #include <gst/base/gstadapter.h>
36 
37 #include <sbIMediaItem.h>
38 #include <sbIMediacoreAudioProcessor.h>
39 #include <sbIMediacoreAudioProcessorListener.h>
40 
41 #include "sbGStreamerPipeline.h"
42 
45 {
46 public:
48  NS_DECL_NSICLASSINFO
49  NS_DECL_SBIMEDIACOREAUDIOPROCESSOR
50 
52 
53 private:
54  virtual ~sbGStreamerAudioProcessor();
55 
56  virtual nsresult BuildPipeline();
57 
58  virtual void HandleMessage(GstMessage *message);
59 
60  virtual nsresult OnDestroyPipeline(GstElement *pipeline);
61 
62  /* Instance methods for GObject signals */
63  nsresult DecoderPadAdded (GstElement *uridecodebin, GstPad *pad);
64  nsresult DecoderNoMorePads (GstElement *uridecodebin);
65  nsresult AppsinkNewBuffer(GstElement *appsink);
66  nsresult AppsinkEOS(GstElement *appsink);
67 
68  /* Static helpers that simply forward to the relevant instance methods */
69  static void decodebin_pad_added_cb (GstElement *element, GstPad *pad,
70  sbGStreamerAudioProcessor *processor);
71  static void decodebin_no_more_pads_cb (GstElement *element,
72  sbGStreamerAudioProcessor *processor);
73  static void appsink_new_buffer_cb (GstElement *element,
74  sbGStreamerAudioProcessor *processor);
75  static void appsink_eos_cb (GstElement *element,
76  sbGStreamerAudioProcessor *processor);
77 
78  /* Misc helper methods */
79 
80  // Configure capsfilter to match the constraints specified via
81  // the sbIMediacoreAudioProcessor interface.
82  nsresult ConfigureInitialCapsfilter(GstElement *capsfilter);
83 
84  // Called once running, reconfigures capsfilter to the current caps, so that
85  // changes in the underlying stream cannot change what we receive.
86  nsresult ReconfigureCapsfilter();
87 
88  // Asynchronously send an event to the listener. May be called from any
89  // thread.
90  nsresult SendEventAsync(PRUint32 eventType, nsIVariant *eventDetails);
91 
92  // Synchronously send an event to the listener. Main thread only.
93  nsresult SendEventSync(PRUint32 eventType, nsIVariant *eventDetails);
94 
95  // Helper to actually send the event; called only on main thread.
96  nsresult SendEventInternal(PRUint32 eventType,
97  nsCOMPtr<nsIVariant> eventDetails);
98 
99  // Asynchronously send an error event, with an associated message looked up
100  // in the string bundle with the given name.
101  nsresult SendErrorEvent(PRUint32 errorCode, const char *errorName);
102 
103  // If we have enough data (either in the adapter, or in mBuffersAvailable (the
104  // latter referring to buffers in mAppSink, plus mPendingBuffer if non-null)),
105  // then schedule that to be sent (we don't send immediately as this might be
106  // called on a non-main thread).
107  nsresult ScheduleSendDataIfAvailable();
108 
109  // Do we have enough data in mAdapter to immediately send it to a listener?
110  PRBool HasEnoughData();
111 
112  // If we can, get more data from the appsink or the pending buffer, and add it
113  // to mAdapter. Must only be called if mBuffersAvailable is > 0.
114  void GetMoreData();
115 
116  // Dispatch a call to SendDataToListener() to the main thread.
117  nsresult ScheduleSendData();
118 
119  // Actually send data to the listener, if not suspended or stopped.
120  // Once data has been sent, calls ScheduleSendDataIfAvailable() to see if we
121  // have enough to send more.
122  void SendDataToListener();
123 
124  // Get the duration in samples from the buffer.
125  PRUint32 GetDurationFromBuffer(GstBuffer *buf);
126 
127  // Get the sample number corresponding to the start of this buffer.
128  PRUint64 GetSampleNumberFromBuffer(GstBuffer *buf);
129 
130  // Handle the things we need to do before we first send data to the listener,
131  // including sending the start event.
132  nsresult DoStreamStart();
133 
134  // Determine what audio format we're going to send to the listener.
135  nsresult DetermineFormat();
136 
137  // The listener. The interface only supports one per instance.
138  nsCOMPtr<sbIMediacoreAudioProcessorListener> mListener;
139 
140  // Our constraints - all zero by default indicating no constraint
141  PRUint32 mConstraintChannelCount;
142  PRUint32 mConstraintSampleRate;
143  PRUint32 mConstraintAudioFormat;
144  PRUint32 mConstraintBlockSize;
145 
146  // Block size is in samples; this stores the value in bytes (which is format
147  // dependent).
148  PRUint32 mConstraintBlockSizeBytes;
149 
150  // The item being processed.
151  nsCOMPtr<sbIMediaItem> mMediaItem;
152 
153  // Monitor used to protect all the following data items, which are modified
154  // from both the main thread and from GStreamer streaming threads.
155  PRMonitor *mMonitor;
156 
157  // Adapter used to ensure that data is sent in chunks sized according to
158  // mConstraintBlockSize.
159  GstAdapter *mAdapter;
160 
161  // The sink element we pull data from.
162  GstAppSink *mAppSink;
163 
164  // The capsfilter element; we keep a reference to this so that we can
165  // reconfigure it later.
166  GstElement *mCapsFilter;
167 
168  // Track whether we're currently suspended or stopped - data will not be
169  // sent to the listener when this is true.
170  PRBool mSuspended;
171 
172  // Track if we've found an audio pad yet. If so, we ignore subsequent audio
173  // tracks (e.g. in a video file with multiple audio tracks).
174  PRBool mFoundAudioPad;
175 
176  // Set once we've fully initialised and sent the EVENT_START event to the
177  // listener. At this point, the format being set is fully determined (see
178  // mAudioFormat, mSampleRate, mChannels)
179  PRBool mHasStarted;
180 
181  // Set if we've reached EOS.
182  PRBool mIsEOS;
183 
184  // Set if we've reached the end of a 'section'. This is any sequence of
185  // contiguous audio data (no gaps in the timestamps, nor explicit gaps from
186  // the DISCONT flag on the audio buffers). We use this to know whether to
187  // drain mAdapter, even if we don't have enough data to satisfy
188  // mConstraintBlockSize, before sending a GAP event.
189  PRBool mIsEndOfSection;
190 
191  // Set if we've already sent an error message, to tell us to suppress further
192  // errors.
193  PRBool mHasSentError;
194 
195  // Set if we should send a GAP event before sending any other data. This will
196  // be set after we've encountered a gap, then drained the data from mAdapter.
197  PRBool mSendGap;
198 
199  // The sample number of the start of the data currently held in mAdapter, that
200  // will be sent to listeners when data is next delivered.
201  PRUint64 mSampleNumber;
202 
203  // The expected sample number of the next audio to be added to mAdapter, this
204  // is equal to mSampleNumber plus the duration in samples of the audio in
205  // mAdapter currently.
206  PRUint64 mExpectedNextSampleNumber;
207 
208  // Once mHasStarted is set, this is the specific audio format in use,
209  // either FORMAT_INT16 or FORMAT_FLOAT.
210  PRUint32 mAudioFormat;
211 
212  // Once mHasStarted is set, this is the sample rate being delivered to the
213  // listener.
214  gint mSampleRate;
215 
216  // Once mHasStarted is set, this is the number of channels being delivered to
217  // the listener.
218  gint mChannels;
219 
220  // The number of buffers available in the appsink and (if non-null) the
221  // one in mPendingBuffer
222  PRUint32 mBuffersAvailable;
223 
224  // A pending buffer. This is (when non-NULL) a buffer we've pulled from the
225  // appsink, but have not yet submitted to mAdapter, because we're waiting for
226  // mAdapter to drain before sending a gap event.
227  // mPendingBuffer is only non-NULL while mIsEndOfSection is true.
228  GstBuffer *mPendingBuffer;
229 
230 };
231 
232 #define SB_GSTREAMER_AUDIO_PROCESSOR_CLASSNAME \
233  "sbGStreamerAudioProcessor"
234 #define SB_GSTREAMER_AUDIO_PROCESSOR_DESCRIPTION \
235  "Songbird GStreamer Audio Processing API Implementation"
236 #define SB_GSTREAMER_AUDIO_PROCESSOR_CONTRACTID \
237  "@songbirdnest.com/Songbird/Mediacore/GStreamer/AudioProcessor;1"
238 #define SB_GSTREAMER_AUDIO_PROCESSOR_CID \
239  {0x490fef6b, 0xfed9, 0x4243, {0xa2, 0x80, 0x6b, 0xb1, 0x8a, 0x28, 0x3d, 0xfa}}
240 
241 #endif // _SB_GSTREAMER_AUDIO_PROCESSOR_H_
242 
NS_DECL_ISUPPORTS NS_DECL_NSICLASSINFO NS_DECL_SBIMEDIACOREAUDIOPROCESSOR sbGStreamerAudioProcessor()
GstMessage * message