Index: media/audio/win/waveout_output_win.h |
=================================================================== |
--- media/audio/win/waveout_output_win.h (revision 110309) |
+++ media/audio/win/waveout_output_win.h (working copy) |
@@ -6,11 +6,16 @@ |
#define MEDIA_AUDIO_WIN_WAVEOUT_OUTPUT_WIN_H_ |
#pragma once |
+#include <map> |
tommi (sloooow) - chröme
2011/11/18 09:53:21
os includes first
enal1
2011/11/19 00:59:19
Done.
|
+ |
#include <windows.h> |
#include <mmsystem.h> |
#include <mmreg.h> |
#include "base/basictypes.h" |
+#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/synchronization/lock.h" |
#include "base/win/scoped_handle.h" |
#include "media/audio/audio_io.h" |
#include "media/audio/audio_parameters.h" |
@@ -29,8 +34,9 @@ |
class PCMWaveOutAudioOutputStream : public AudioOutputStream { |
public: |
// The ctor takes all the usual parameters, plus |manager| which is the |
- // the audio manager who is creating this object and |device_id| which |
- // is provided by the operating system. |
+ // the audio manager who is creating this object and on which message loop |
+ // "feeder" callbacks are running, and |device_id| which is provided by the |
+ // operating system. |
PCMWaveOutAudioOutputStream(AudioManagerWin* manager, |
const AudioParameters& params, |
int num_buffers, |
@@ -49,27 +55,73 @@ |
void QueueNextPacket(WAVEHDR* buffer); |
private: |
+ // Returns pointer to the n-th buffer. |
+ WAVEHDR* GetBuffer(int n) const { |
tommi (sloooow) - chröme
2011/11/18 09:53:21
nice. you could move this to the cc file to avoid
enal1
2011/11/19 00:59:19
Done.
|
+ DCHECK_GE(n, 0); |
+ DCHECK_LT(n, num_buffers_); |
+ return reinterpret_cast<WAVEHDR*>(buffers_ + n * CbBuffer()); |
+ } |
+ |
enum State { |
PCMA_BRAND_NEW, // Initial state. |
PCMA_READY, // Device obtained and ready to play. |
PCMA_PLAYING, // Playing audio. |
+ PCMA_STOPPING, // Stopping the audio. |
PCMA_CLOSED // Device has been released. |
}; |
- // Windows calls us back to feed more data to the device here. See msdn |
- // documentation for 'waveOutProc' for details about the parameters. |
+ // Size of one buffer in bytes, rounded up to the nearest 16 bytes. |
+ DWORD CbBuffer() const { |
tommi (sloooow) - chröme
2011/11/18 09:53:21
CbBuffer -> BufferSize
Also, return size_t?
enal1
2011/11/19 00:59:19
Done.
|
+ return (sizeof(WAVEHDR) + buffer_size_ + 15u) & static_cast<DWORD>(-16); |
tommi (sloooow) - chröme
2011/11/18 09:53:21
instead of static_cast<DWORD>(-16), can you just u
enal1
2011/11/19 00:59:19
In general, 0xFFFFFFF0 is bad -- it can become a p
|
+ } |
+ |
+ // Windows calls us back to free the buffer. See msdn documentation for |
+ // 'waveOutProc' for details about the parameters. |
static void CALLBACK WaveCallback(HWAVEOUT hwo, UINT msg, DWORD_PTR instance, |
DWORD_PTR param1, DWORD_PTR param2); |
+ // Feed the buffer to waveOut. |
+ // Called on the audio manager thread. |
+ static void FeedBuffer(PCMWaveOutAudioOutputStream* stream, |
+ WAVEHDR* buffer, |
+ HWAVEOUT hwo, |
+ DWORD ordinal); |
+ |
// If windows reports an error this function handles it and passes it to |
// the attached AudioSourceCallback::OnError(). |
void HandleError(MMRESULT error); |
- // Allocates and prepares the memory that will be used for playback. Only |
- // two buffers are created. |
+ // Allocates and prepares the memory that will be used for playback. |
tommi (sloooow) - chröme
2011/11/18 09:53:21
add an empty line above this one. same throughout
enal1
2011/11/19 00:59:19
Done.
|
void SetupBuffers(); |
// Deallocates the memory allocated in SetupBuffers. |
void FreeBuffers(); |
+ // Globals-related functions. |
tommi (sloooow) - chröme
2011/11/18 09:53:21
This comment isn't very useful. Can you document
enal1
2011/11/19 00:59:19
Done.
|
+ static void InitializeGlobalsIfNecessary(); |
+ static void CleanupGlobals(void* not_used); |
+ // Static lock guarding access to globals. |
+ // We are not doing any expensive operations under this lock -- |
+ // adding/searching/removing object to/in/from map of all live objects, and |
+ // trying to acquire object lock, so hopefully we can live with one global |
+ // lock for all audio streams. If contention ever becomes the problem we |
+ // can use hash of stream address to use one of several global locks. |
+ static base::Lock g_lock_; |
tommi (sloooow) - chröme
2011/11/18 09:53:21
We should avoid global objects that require constr
enal1
2011/11/19 00:59:19
Done.
|
+ |
+ // When playing, every instance of our audio stream has associated ordinal. |
+ // Callback that feeds the audio thread verifies that stream is still alive |
+ // by looking stream address and its ordinal in the map of all streams. |
tommi (sloooow) - chröme
2011/11/18 09:53:21
by looking stream address -> by looking at the str
enal1
2011/11/19 00:59:19
Done.
|
+ // Stream is not touched before check is complete. This way we don't |
tommi (sloooow) - chröme
2011/11/18 09:53:21
"Stream is not touched before check is complete"
enal1
2011/11/19 00:59:19
Done.
|
+ // have to wait for all scheduled callbacks to finish when stopping audio |
+ // stream. Ordinal is needed because audio stream can be deleted and new one |
+ // with same address created. |
+ // Ordinal overflow would be a problem only if some scheduled feeder callback |
+ // would not run before 4.2*10**9 play() calls are executed, impossible for |
+ // now... |
+ static volatile DWORD g_ordinal_; |
+ |
+ // Map of all live streams with their ordinals. |
+ static scoped_ptr<std::map<PCMWaveOutAudioOutputStream*, DWORD> > |
+ g_streams_map_; |
+ |
// Reader beware. Visual C has stronger guarantees on volatile vars than |
// most people expect. In fact, it has release semantics on write and |
// acquire semantics on reads. See the msdn documentation. |
@@ -107,19 +159,17 @@ |
// Handle to the instance of the wave device. |
HWAVEOUT waveout_; |
- // Pointer to the first allocated audio buffer. This object owns it. |
- WAVEHDR* buffer_; |
+ // Pointer to the allocated audio buffers, we allocate all buffers in one big |
+ // chunk. Stream owns them. |
tommi (sloooow) - chröme
2011/11/18 09:53:21
I prefer "This object owns it" to "Stream owns the
|
+ char* buffers_; |
- // Lock used to prevent stopping the hardware callback thread while it is |
- // pending for data or feeding it to audio driver, because doing that causes |
- // the deadlock. Main thread gets that lock before stopping the playback. |
- // Callback tries to acquire that lock before entering critical code. If |
- // acquire fails then main thread is stopping the playback, callback should |
- // immediately return. |
- // Use Windows-specific lock, not Chrome one, because there is limited set of |
- // functions callback can use. |
- CRITICAL_SECTION lock_; |
+ // Lock used to avoid the conflict between filling audio buffers and |
+ // stopping the stream. |
+ base::Lock lock_; |
+ // Ordinal of current stream when playing. |
+ DWORD ordinal_; |
+ |
DISALLOW_COPY_AND_ASSIGN(PCMWaveOutAudioOutputStream); |
}; |