summaryrefslogtreecommitdiff
path: root/chromium/media/audio/win/waveout_output_win.h
blob: b97eb95b429be9f660b9fc9aa5168dd24ab1f97f (plain)
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
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_AUDIO_WIN_WAVEOUT_OUTPUT_WIN_H_
#define MEDIA_AUDIO_WIN_WAVEOUT_OUTPUT_WIN_H_

#include <windows.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <stddef.h>
#include <stdint.h>

#include <memory>

#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/win/scoped_handle.h"
#include "media/audio/audio_io.h"
#include "media/base/audio_parameters.h"

namespace media {

class AudioManagerWin;

// Implements PCM audio output support for Windows using the WaveXXX API.
// While not as nice as the DirectSound-based API, it should work in all target
// operating systems regardless or DirectX version installed. It is known that
// in some machines WaveXXX based audio is better while in others DirectSound
// is better.
//
// Important: the OnXXXX functions in AudioSourceCallback are called by more
// than one thread so it is important to have some form of synchronization if
// you are keeping state in it.
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.
  PCMWaveOutAudioOutputStream(AudioManagerWin* manager,
                              const AudioParameters& params,
                              int num_buffers,
                              UINT device_id);

  PCMWaveOutAudioOutputStream(const PCMWaveOutAudioOutputStream&) = delete;
  PCMWaveOutAudioOutputStream& operator=(const PCMWaveOutAudioOutputStream&) =
      delete;

  ~PCMWaveOutAudioOutputStream() override;

  // Implementation of AudioOutputStream.
  bool Open() override;
  void Close() override;
  void Flush() override;
  void Start(AudioSourceCallback* callback) override;
  void Stop() override;
  void SetVolume(double volume) override;
  void GetVolume(double* volume) override;

  // Sends a buffer to the audio driver for playback.
  void QueueNextPacket(WAVEHDR* buffer);

 private:
  enum State {
    PCMA_BRAND_NEW,    // Initial state.
    PCMA_READY,        // Device obtained and ready to play.
    PCMA_PLAYING,      // Playing audio.
    PCMA_STOPPING,     // Audio is stopping, do not "feed" data to Windows.
    PCMA_CLOSED        // Device has been released.
  };

  // Returns pointer to the n-th buffer.
  inline WAVEHDR* GetBuffer(int n) const;

  // Size of one buffer in bytes, rounded up if necessary.
  inline size_t BufferSize() const;

  // Windows calls us back asking for more data when buffer_event_ signalled.
  // See MSDN for help on RegisterWaitForSingleObject() and waveOutOpen().
  static void NTAPI BufferCallback(PVOID lpParameter, BOOLEAN timer_fired);

  // If windows reports an error this function handles it and passes it to
  // the attached AudioSourceCallback::OnError(ErrorType type).
  void HandleError(MMRESULT error);

  // Allocates and prepares the memory that will be used for playback.
  void SetupBuffers();

  // Deallocates the memory allocated in SetupBuffers.
  void FreeBuffers();

  // 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.
  volatile State state_;

  // The audio manager that created this output stream. We notify it when
  // we close so it can release its own resources.
  AudioManagerWin* manager_;

  // We use the callback mostly to periodically request more audio data.
  AudioSourceCallback* callback_;

  // The number of buffers of size |buffer_size_| each to use.
  const int num_buffers_;

  // The size in bytes of each audio buffer, we usually have two of these.
  uint32_t buffer_size_;

  // Volume level from 0 to 1.
  float volume_;

  // Channels from 0 to 8.
  const int channels_;

  // Number of bytes yet to be played in the hardware buffer.
  uint32_t pending_bytes_;

  // The id assigned by the operating system to the selected wave output
  // hardware device. Usually this is just -1 which means 'default device'.
  UINT device_id_;

  // Windows native structure to encode the format parameters.
  WAVEFORMATPCMEX format_;

  // Handle to the instance of the wave device.
  HWAVEOUT waveout_;

  // Handle to the buffer event.
  base::win::ScopedHandle buffer_event_;

  // Handle returned by RegisterWaitForSingleObject().
  HANDLE waiting_handle_;

  // Pointer to the allocated audio buffers, we allocate all buffers in one big
  // chunk. This object owns them.
  std::unique_ptr<char[]> buffers_;

  // Lock used to avoid the conflict when callbacks are called simultaneously.
  base::Lock lock_;

  // Container for retrieving data from AudioSourceCallback::OnMoreData().
  std::unique_ptr<AudioBus> audio_bus_;
};

}  // namespace media

#endif  // MEDIA_AUDIO_WIN_WAVEOUT_OUTPUT_WIN_H_