File: AEDeviceEnumerationOSX.h

package info (click to toggle)
kodi 2%3A20.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 143,820 kB
  • sloc: cpp: 664,925; xml: 68,398; ansic: 37,223; python: 6,903; sh: 4,209; javascript: 2,325; makefile: 1,754; perl: 969; java: 513; cs: 390; objc: 340
file content (246 lines) | stat: -rw-r--r-- 10,386 bytes parent folder | download | duplicates (2)
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
/*
 *  Copyright (C) 2014-2018 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#pragma once

#include "cores/AudioEngine/Sinks/osx/CoreAudioDevice.h"
#include "cores/AudioEngine/Utils/AEAudioFormat.h"
#include "cores/AudioEngine/Utils/AEDeviceInfo.h"

#include <string>
#include <utility>
#include <vector>

struct CADeviceInstance
{
  AudioDeviceID audioDeviceId;
  unsigned int streamIndex;
  unsigned int sourceId;
};
typedef std::vector< std::pair<struct CADeviceInstance, CAEDeviceInfo> > CADeviceList;

//Hierarchy:
// Device
//       - 1..n streams
//            1..n formats
//       - 0..n sources
//on non planar devices we have numstreams * numsources devices for our list
//on planar devices we have 1 * numsources devices for our list
class AEDeviceEnumerationOSX
{
public:
  /*!
  * @brief C'tor - initialises the Enumerator and calls Enumerate
  * @param  deviceID - the CoreAudio Device ID which will be the base of the enumerated device list
  */
  AEDeviceEnumerationOSX(AudioDeviceID deviceID);
  // d'tor
  ~AEDeviceEnumerationOSX() = default;

  /*!
  * @brief Gets the device list which was enumerated by the last call to Enumerate
  *        (which is also called in c'tor).
  *
  * @return Returns the device list.
  */
  CADeviceList  GetDeviceInfoList() const;

  /*!
  * @brief Fetches all metadata from the CoreAudio device which is needed to generate a proper DeviceList for AE
  *        This method is always called from C'tor but can be called multiple times if the streams of a device
  *        changed. This fills m_caStreamInfos.
  *        After this call - GetDeviceInfoList will reflect the Enumerated metadata.
  * @return false when streamlist couldn't be fetched from device - else true
  */
  bool          Enumerate();

  /*!
  * @brief Returns the number of Planes for a device. This will be 1 for non-planar devices and > 1 for planar devices.
  * @return Number of planes for this device.
  */
  unsigned int  GetNumPlanes() const;

  /*!
  * @brief Checks if the m_deviceID belongs to a planar or non-planar device.
  * @return true if m_deviceID belongs to a planar device - else false.
  */
  bool          IsPlanar() const { return m_isPlanar; }

  /*!
  * @brief Tries to find a suitable CoreAudio format which matches the given AEAudioFormat as close as possible.
  * @param streamIdx [in/out] - if streamIdx != INT_MAX only formats of the given streamIdx are checked
  *                             if streamIdx == INT_MAX - formats of all streams in the device are considered
  *                             On success this parameter returns the selected streamIdx.
  *
  * @param format    [in]     - the requested AE format which should be matched to the stream formats of CA
  * @param outputFormat [out] - the found CA format which matches best to the requested AE format
  * @param outputStream [out] - the coreaudio streamid which contains the coreaudio format returned in outputFormat
  * @return true if a matching corea audio format was found - else false
  */
  bool          FindSuitableFormatForStream(UInt32 &streamIdx, const AEAudioFormat &format, bool virt,
                                            AudioStreamBasicDescription &outputFormat,
                                            AudioStreamID &outputStream) const;

  /*!
  * @brief Returns the device name which belongs to m_deviceID without any stream/source suffixes
  * @return the CA device name
  */
  std::string   GetMasterDeviceName() const { return m_deviceName; }

  /*!
  * @brief Tries to return a proper channelmap from CA in a format AE understands
  * @param channelMap [in/out] - returns the found channelmap in AE format
  *                              if initialised with a map the number of channels is used to determine
  *                              if stereo or multichannel map should be fetched
  * @param channelsPerFrame [int] - the number of channels which should be mapped
  *                                 (also decides if stereo or multichannel map is fetched similar to channelMap param)
  */
  void          GetAEChannelMap(CAEChannelInfo &channelMap, unsigned int channelsPerFrame) const;

  /*!
   * @brief Scores a format based on:
   *   1. Matching passthrough characteristics (i.e. passthrough flag)
   *   2. Matching sample rate.
   *   3. Matching bits per channel (or higher).
   *   4. Matching number of channels (or higher).
   *
   * @param formatDesc   [in] - The CA FormatDescription which should be scored
   * @param format [in] - the AE format which should be matched as good as possible
   * @return - the score of formatDesc - higher scores indicate better matching to "format"
   *          (scores > 10000 indicate passthrough formats)
   */
  // public because its used in unit tests ...
  float             ScoreFormat(const AudioStreamBasicDescription &formatDesc, const AEAudioFormat &format) const;

private:

  /*!
  * @brief Checks if this is a digital device based on CA transportType or name
  * @return - true if this is a digital device - else false.
  */
  bool              isDigitalDevice() const;

  /*!
  * @brief Checks if there are passthrough formats or digital formats
  *       (the latter are passthrough formats with dedicated format config like AC3/DTS)
  * @param formatList [in] - the format list to be evaluated
  * @param hasPassthroughFormats [out] - true if there were passthrough formats in the list
  * @param hasDigitalFormat [out] - true if there were dedicated passthrough formats in the list
  */
  void              hasPassthroughOrDigitalFormats(const StreamFormatList &formatList,
                                                   bool &hasPassthroughFormats,
                                                   bool &hasDigitalFormat) const;

  /*!
  * @brief Gets the AE devicetype for this device based the given criteria
  * @param hasPassthroughFormats [in] - flag indicating that the device has passthrough formats
  * @param isDigital [in] - flag indicating that the device is digital
  * @param numChannels [in] - the number of channels of the device
  * @param transportType [in] - the transportType of the device
  * @return the AE devicetype
  */
  enum AEDeviceType getDeviceType(bool hasPassthroughFormats, bool isDigital,
                                  UInt32 numChannels, UInt32 transportType) const;

  /*!
  * @brief Fetches all ca streams from the ca device and fills m_channelsPerStream and m_streams
  */
  void              fillStreamList();

  /*!
  * @brief Scores a samplerate based on:
  * 1. Prefer exact match
  * 2. Prefer exact multiple of source samplerate and prefer the lowest
  *
  * @param destinationRate [in] - the destination samplerate to score
  * @param sourceRate [in] - the sourceRate of the audio format - this is the samplerate the score is based on
  * @return the score
  */
  float             scoreSampleRate(Float64 destinationRate, unsigned int sourceRate) const;

  bool              hasSampleRate(const AESampleRateList &list, const unsigned int samplerate) const;
  bool              hasDataFormat(const AEDataFormatList &list, const enum AEDataFormat format) const;
  bool              hasDataType(const AEDataTypeList &list, CAEStreamInfo::DataType type) const;

  /*!
  * @brief Converts a CA format description to a list of AEFormat descriptions (as one format can result
  *        in more then 1 AE format - e.x. AC3 ca format results in AC3 and DTS AE format
  *
  * @param formatDesc [in] - The CA format description to be converted
  * @param isDigital  [in] - Flag indicating if the parent stream of formatDesc is digital
  *                        (for allowing bitstreaming without dedicated AC3 format in CA)
  * @return The list of converted AE formats.
  */
  AEDataFormatList  caFormatToAE(const AudioStreamBasicDescription &formatDesc, bool isDigital) const;
  AEDataTypeList caFormatToAEType(const AudioStreamBasicDescription &formatDesc, bool isDigital) const;


  /*!
  * @brief Convert a CA channel label to an AE channel.
  * @param CAChannelLabel - the CA channel label to be converted
  * @return the corresponding AEChannel
  */
  enum AEChannel    caChannelToAEChannel(const AudioChannelLabel &CAChannelLabel) const;

  // for filling out the AEDeviceInfo object based on
  // the data gathered on the last call to Enumerate()
  /*!
  * @brief Returns all AE formats for the CA stream at the given index
  * @param streamIdx [in] - index into m_caStreamInfos
  * @return - the list of AE formats in that stream.
  */
  AEDataFormatList  getFormatListForStream(UInt32 streamIdx) const;

  AEDataTypeList  getTypeListForStream(UInt32 streamIdx) const;

  /*!
  * @brief Returns the AE channelinfo/channel map for the CA stream at the given index
  * @param streamIdx [in] - index into m_caStreamInfos
  * @return - the of AE channel info for that stream.
  */
  CAEChannelInfo    getChannelInfoForStream(UInt32 streamIdx) const;

  /*!
  * @brief Returns the AE samplerates for the CA stream at the given index
  * @param streamIdx [in] - index into m_caStreamInfos
  * @return - the list of AE samplerates for that stream.
  */
  AESampleRateList  getSampleRateListForStream(UInt32 streamIdx) const;

  /*!
  * @brief Returns the AE device name for the CA stream at the given index
  * @param streamIdx [in] - index into m_caStreamInfos
  * @return - The devicename for that stream
  */
  std::string       getDeviceNameForStream(UInt32 streamIdx) const;

  /*!
  * @brief - Returns the extra displayname shown to the User in addition to getDisplayNameForStream
  *          for the CA stream at the given index
  * @param streamIdx [in] - index into m_caStreamInfos
  * @return - The extra displayname for that stream (might be empty)
  */
  std::string       getExtraDisplayNameForStream(UInt32 streamIdx) const;

  AudioDeviceID     m_deviceID;
  bool              m_isPlanar;
  std::string       m_deviceName;

  typedef struct
  {
    AudioStreamID streamID;
    StreamFormatList formatList;
    StreamFormatList formatListVirt;
    UInt32 numChannels;
    bool isDigital;
    bool hasPassthroughFormats;
    enum AEDeviceType deviceType;
  } caStreamInfo;
  std::vector<caStreamInfo>       m_caStreamInfos;
  CCoreAudioDevice                m_caDevice;
};