-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio.h
More file actions
336 lines (266 loc) · 10.1 KB
/
audio.h
File metadata and controls
336 lines (266 loc) · 10.1 KB
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* audio.h:
*
* Contact:
* Moonlight List (moonlight-list@lists.ximian.com)
*
* Copyright 2008 Novell, Inc. (http://www.novell.com)
*
* See the LICENSE file included with the distribution for details.
*/
#ifndef __AUDIO_H__
#define __AUDIO_H__
namespace Moonlight {
class AudioStream;
class MediaPlayer;
class MediaFrame;
class AudioSource;
class AudioSources;
class AudioPlayer;
class AudioRecorder;
};
#include "dependencyobject.h"
#include "pipeline.h"
namespace Moonlight {
// uncomment to dump raw audio data to /tmp.
// the exact command to play the raw audio file will be printed to stdout
// #define DUMP_AUDIO
enum AudioFlags {
// The AudioSource has been initialized correctly.
// This flag is removed if SetState (AudioError) is called.
AudioInitialized = 1 << 0,
// The audio source has run out of data to write (the last frame had FrameEventEOF set).
// There still may be samples in the pipeline somewhere causing audio to be played.
// This flag is removed when AppendFrame is called.
AudioEOF = 1 << 1,
// The audio source has run out of data to write, and is waiting for more.
// There still may be samples in the pipeline somewhere causing audio to be played.
// This flag is removed when AppendFrame is called.
AudioWaiting = 1 << 2,
// The audio source has run out of data to write and has played all available samples.
// This flag is removed when Play/Pause/Stop/AppendFrame is called.
AudioEnded = 1 << 3,
};
enum AudioState {
AudioNone, // Initial state.
AudioError, // An error has occured.
AudioPlaying, // Play has been called
AudioPaused, // Pause has been called
AudioStopped, // Stop has been called (or we've played all the available data).
};
struct AudioData {
void *dest; // Audio samples
gint32 distance; // The distance between samples (in bytes)
};
// All AudioSource's public methods must be safe to call from any thread.
class AudioSource : public EventObject {
private:
struct AudioFrame {
MediaFrame *frame;
guint32 bytes_used;
AudioFrame (MediaFrame *frame);
~AudioFrame ();
};
MediaPlayer *mplayer;
AudioStream *stream;
AudioPlayer *player;
AudioFrame *current_frame;
AudioState state;
AudioFlags flags;
double balance;
double volume;
bool muted;
guint64 last_write_pts; // The last pts written
guint64 last_current_pts; // The last value returned from GetCurrentPts
guint32 channels; // The number of channels
guint32 sample_rate; // The sample rate in the audio source
guint32 input_bytes_per_sample; // The number of bytes per sample
guint32 output_bytes_per_sample; // The number of bytes per sample in the output. Defaults to same as input_bytes_per_sample.
MoonMutex mutex;
void Lock ();
void Unlock ();
MediaPlayer *GetMediaPlayerReffed ();
EVENTHANDLER (AudioSource, FirstFrameEnqueued, EventObject, EventArgs);
#ifdef DUMP_AUDIO
FILE *dump_fd;
#endif
protected:
/* @SkipFactories */
AudioSource (Type::Kind type, AudioPlayer *player, MediaPlayer *mplayer, AudioStream *stream);
virtual ~AudioSource ();
// Writes frames to the specified destination
// Returns the number of frames actually written
// frame: consists of 1 audio sample of input_bytes_per_sample bytes * number of channels
guint32 Write (void *dest, guint32 samples);
guint32 WriteFull (AudioData **channel_data /* Array of info about channels, NULL ended. */, guint32 samples);
virtual void Played () { }
virtual void Paused () { }
virtual void Stopped () { }
// The deriving class must call this method when it has finished playing
// all the written samples.
void Underflowed ();
// Called whenever the state changes
virtual void StateChanged (AudioState old_state) {}
// Must return the time difference between the last written sample
// and what the audio hw is playing now (in pts).
// This method will only be called if GetState () == AudioPlaying
// Must return G_MAXUINT64 in case of any errors.
virtual guint64 GetDelayInternal () = 0;
virtual bool InitializeInternal () { return true; }
// There's no guarantee CloseInternal won't be called more than once.
virtual void CloseInternal () {};
public:
virtual void Dispose ();
void Play ();
void Pause ();
void Stop ();
guint64 GetDelay ();
// Initialize(Internal) is called before adding the source to the list of sources
// If Initialize fails (returns false), the source is not added to the list of sources.
bool Initialize ();
// Close(Internal) is called after removing the source from the list of sources
void Close ();
// This method may return G_MAXUINT64 if it has no idea which is the current pts.
// This may happen if nothing has been done yet (the derived audio source hasn't
// requested any writes).
guint64 GetCurrentPts ();
guint32 GetInputBytesPerFrame ();
guint32 GetOutputBytesPerFrame ();
guint32 GetInputBytesPerSample ();
guint32 GetOutputBytesPerSample ();
/* This method must only be called during initilization so that output_bytes_per_sample is thread-safe without locking */
void SetOutputBytesPerSample (guint32 value);
AudioStream *GetStreamReffed ();
bool IsQueueEmpty ();
AudioState GetState ();
void SetState (AudioState value);
static const char *GetStateName (AudioState state);
void SetFlag (AudioFlags, bool value);
bool GetFlag (AudioFlags flag);
#if LOGGING
AudioFlags GetFlags () { return flags; }
static const char *GetFlagNames (AudioFlags flags);
#endif
guint32 GetChannels ();
guint32 GetSampleRate ();
double GetBalance ();
void SetBalance (double value);
double GetVolume ();
void SetVolume (double value);
bool GetMuted ();
void SetMuted (bool value);
void SetAudioStream (AudioStream *value);
AudioStream *GetAudioStream ();
bool IsPlaying () { return GetState () == AudioPlaying && !GetFlag (AudioWaiting); }
virtual const char *GetTypeName () { return "AudioSource"; }
};
class AudioListNode : public List::Node {
public:
AudioSource *source;
gint32 generation;
AudioListNode (AudioSource *source);
virtual ~AudioListNode ();
};
class AudioSources {
MoonMutex mutex;
List list;
gint32 current_generation;
AudioListNode *last_node; // The last node returned by GetNext.
void Lock ();
void Unlock ();
public:
AudioSources ();
~AudioSources ();
void Add (AudioSource *node);
// Returns true if the node existed in the list
bool Remove (AudioSource *node);
// Enumerating all sources:
// First call StartEnumeration, then call GetNext until NULL is returned.
// Only one enumeration can be going at the same time, otherwise they'll
// interfere with eachother.
// GetNext returns the AudioSource reffed, the caller must unref.
void StartEnumeration ();
AudioSource *GetNext (bool only_playing);
// Returns the first AudioSource in the list (reffed, the caller must unref)
// Returns NULL if the list is empty.
AudioSource *GetHead ();
#if DEBUG
int Length ();
#endif
};
class AudioRecorder : public EventObject {
AudioCaptureDevice *device;
protected:
/* @SkipFactories */
AudioRecorder (Type::Kind object_type);
AudioCaptureDevice *GetDevice (); // main thread only
virtual ~AudioRecorder () {}
public:
virtual void Record () = 0;
// Stop must not return until recording has actually stopped,
// and a derived implementation can not call GetDevice after Stop has been called.
virtual void Stop () = 0;
virtual void GetSupportedFormats (AudioFormatCollection *col) = 0;
virtual const char *GetFriendlyName () = 0;
void SetDevice (AudioCaptureDevice *device);
};
class AudioPlayer {
// our AudioPlayer instance
static AudioPlayer *instance;
static MoonMutex instance_mutex;
static AudioPlayer *CreatePlayer ();
AudioSource *AddImpl (MediaPlayer *mplayer, AudioStream *stream);
void RemoveImpl (AudioSource *node);
void ShutdownImpl ();
static AudioPlayer *GetInstance ();
/*
* We use our own refcounting here, since we can't derive from EventObject
* (which is always a per deployment object, while AudioPlayer is per-process).
* As with EventObject, the AudioPlayer will be deleted once refcount reaches 0.
*/
gint32 refcount;
void ref ();
void unref ();
protected:
// The list of all the audio sources.
// This is protected so that derived classes can enumerate the sources,
// derived classes must not add/remove sources.
AudioSources sources;
AudioPlayer ();
virtual ~AudioPlayer () {}
virtual void Dispose ();
// called after the node has been created and added to the list of sources
virtual void AddInternal (AudioSource *node) = 0;
// called after the node has been removed from the list of sources, but before the node is deleted.
// not called if the node isn't in the list of sources.
virtual void RemoveInternal (AudioSource *node) = 0;
// called just after ctor.
virtual bool Initialize () = 0;
// before all the nodes will be removedthis method is called
// to ensure that we have stopped the play loop
virtual void PrepareShutdownInternal () = 0;
// all the nodes will have been removed when this method is called
// after this call has returned, the player will be deleted immediately.
virtual void FinishShutdownInternal () = 0;
// Must return a new AudioSource specific for each backend.
virtual AudioSource *CreateNode (MediaPlayer *mplayer, AudioStream *stream) = 0;
// Creates audio recorders, one per device we can record from
virtual guint32 CreateRecordersInternal (AudioRecorder **recorders, guint32 size) { return 0; }
public:
// Creates a audio source from the MediaPlayer and AudioStream.
// Returns NULL if there were any errors.
// Note: Actually returning an object doesn't mean audio will be played.
// some backends are async and will only cause an error to be raised
// later (in which case the AudioSource's state would be AudioError)
static AudioSource *Add (MediaPlayer *mplayer, AudioStream *stream);
// Removes an audio source.
static void Remove (AudioSource *source);
// Shuts down the audio engine
static void Shutdown ();
// Creates audio recorders, one per device we can record from
// the number of recorders will be returned
static guint32 CreateRecorders (AudioRecorder **recorders, guint32 size);
};
};
#endif /* __AUDIO_H__ */