[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / cores / AudioEngine / Engines / CoreAudio / CoreAudioChannelLayout.cpp
1 /*
2  *      Copyright (C) 2011-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "CoreAudioChannelLayout.h"
22
23 #include <AudioToolbox/AudioToolbox.h>
24
25 #define MAX_CHANNEL_LABEL 15
26
27 const char* g_ChannelLabels[] =
28 {
29   "Unused",           // kAudioChannelLabel_Unused
30   "Left",             // kAudioChannelLabel_Left
31   "Right",            // kAudioChannelLabel_Right
32   "Center",           // kAudioChannelLabel_Center
33   "LFE",              // kAudioChannelLabel_LFEScreen
34   "Side Left",        // kAudioChannelLabel_LeftSurround
35   "Side Right",       // kAudioChannelLabel_RightSurround
36   "Left Center",      // kAudioChannelLabel_LeftCenter
37   "Right Center",     // kAudioChannelLabel_RightCenter
38   "Back Center",      // kAudioChannelLabel_CenterSurround
39   "Back Left",        // kAudioChannelLabel_LeftSurroundDirect
40   "Back Right",       // kAudioChannelLabel_RightSurroundDirect
41   "Top Center",       // kAudioChannelLabel_TopCenterSurround
42   "Top Back Left",    // kAudioChannelLabel_VerticalHeightLeft
43   "Top Back Center",  // kAudioChannelLabel_VerticalHeightCenter
44   "Top Back Right",   // kAudioChannelLabel_VerticalHeightRight
45 };
46
47 CCoreAudioChannelLayout::CCoreAudioChannelLayout() :
48   m_pLayout(NULL)
49 {
50 }
51
52 CCoreAudioChannelLayout::CCoreAudioChannelLayout(AudioChannelLayout& layout) :
53 m_pLayout(NULL)
54 {
55   CopyLayout(layout);
56 }
57
58 CCoreAudioChannelLayout::~CCoreAudioChannelLayout()
59 {
60   free(m_pLayout);
61 }
62
63 bool CCoreAudioChannelLayout::CopyLayout(AudioChannelLayout& layout)
64 {
65   enum {
66     kVariableLengthArray_deprecated = 1
67   };
68
69     free(m_pLayout);
70   m_pLayout = NULL;
71
72   // This method always produces a layout with a ChannelDescriptions structure
73
74   OSStatus ret = 0;
75   UInt32 channels = GetChannelCountForLayout(layout);
76   UInt32 size = sizeof(AudioChannelLayout) + (channels - kVariableLengthArray_deprecated) * sizeof(AudioChannelDescription);
77
78   if (layout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
79   {
80     // We can copy the whole layout
81     m_pLayout = (AudioChannelLayout*)malloc(size);
82     memcpy(m_pLayout, &layout, size);
83   }
84   else if (layout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
85   {
86     // Deconstruct the bitmap to get the layout
87     UInt32 propSize = 0;
88     AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForBitmap, sizeof(layout.mChannelBitmap), &layout.mChannelBitmap, &propSize);
89     m_pLayout = (AudioChannelLayout*)malloc(propSize);
90     ret = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap, sizeof(layout.mChannelBitmap), &layout.mChannelBitmap, &propSize, m_pLayout);
91     m_pLayout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
92   }
93   else
94   {
95     // Convert the known layout to a custom layout
96     UInt32 propSize = 0;
97     AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag,
98       sizeof(layout.mChannelLayoutTag), &layout.mChannelLayoutTag, &propSize);
99     m_pLayout = (AudioChannelLayout*)malloc(propSize);
100     ret = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
101       sizeof(layout.mChannelLayoutTag), &layout.mChannelLayoutTag, &propSize, m_pLayout);
102     m_pLayout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
103   }
104
105   return (ret == noErr);
106 }
107
108 UInt32 CCoreAudioChannelLayout::GetChannelCountForLayout(AudioChannelLayout& layout)
109 {
110   UInt32 channels = 0;
111   if (layout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
112   {
113     // Channels are in fixed-order('USB Order'), any combination
114     UInt32 bitmap = layout.mChannelBitmap;
115     for (UInt32 c = 0; c < (sizeof(layout.mChannelBitmap) << 3); c++)
116     {
117       if (bitmap & 0x1)
118         channels++;
119       bitmap >>= 1;
120     }
121   }
122   else if (layout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
123   {
124     // Channels are in any order, any combination
125     channels = layout.mNumberChannelDescriptions;
126   }
127   else
128   {
129     // Channels are in a predefined order and combination
130     channels = AudioChannelLayoutTag_GetNumberOfChannels(layout.mChannelLayoutTag);
131   }
132
133   return channels;
134 }
135
136 const char* CCoreAudioChannelLayout::ChannelLabelToString(UInt32 label)
137 {
138   if (label > MAX_CHANNEL_LABEL)
139     return "Unknown";
140   return g_ChannelLabels[label];
141 }
142
143 const char* CCoreAudioChannelLayout::ChannelLayoutToString(AudioChannelLayout& layout, std::string& str)
144 {
145   AudioChannelLayout* pLayout = NULL;
146
147   if (layout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
148   {
149     pLayout = &layout;
150   }
151   else if (layout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
152   {
153     // Deconstruct the bitmap to get the layout
154     UInt32 propSize = 0;
155     AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForBitmap,
156       sizeof(layout.mChannelBitmap), &layout.mChannelBitmap, &propSize);
157     pLayout = (AudioChannelLayout*)calloc(propSize, 1);
158     AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
159       sizeof(layout.mChannelBitmap), &layout.mChannelBitmap, &propSize, pLayout);
160   }
161   else
162   {
163     // Predefinied layout 'tag'
164     UInt32 propSize = 0;
165     AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag,
166       sizeof(layout.mChannelLayoutTag), &layout.mChannelLayoutTag, &propSize);
167     pLayout = (AudioChannelLayout*)calloc(propSize, 1);
168     AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
169       sizeof(layout.mChannelLayoutTag), &layout.mChannelLayoutTag, &propSize, pLayout);
170   }
171
172   for (UInt32 c = 0; c < pLayout->mNumberChannelDescriptions; c++)
173   {
174     str += "[";
175     str += ChannelLabelToString(pLayout->mChannelDescriptions[c].mChannelLabel);
176     str += "] ";
177   }
178
179   if (layout.mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions)
180     free(pLayout);
181
182   return str.c_str();
183 }
184
185 bool CCoreAudioChannelLayout::AllChannelUnknown()
186 {
187   AudioChannelLayout* pLayout = NULL;
188
189   if (!m_pLayout)
190     return false;
191
192   if (m_pLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
193   {
194     pLayout = m_pLayout;
195   }
196   else if (m_pLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
197   {
198     // Deconstruct the bitmap to get the layout
199     UInt32 propSize = 0;
200     AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForBitmap,
201       sizeof(m_pLayout->mChannelBitmap), &m_pLayout->mChannelBitmap, &propSize);
202     pLayout = (AudioChannelLayout*)calloc(propSize, 1);
203     AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
204       sizeof(m_pLayout->mChannelBitmap), &m_pLayout->mChannelBitmap, &propSize, pLayout);
205   }
206   else
207   {
208     // Predefinied layout 'tag'
209     UInt32 propSize = 0;
210     AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag,
211       sizeof(m_pLayout->mChannelLayoutTag), &m_pLayout->mChannelLayoutTag, &propSize);
212     pLayout = (AudioChannelLayout*)calloc(propSize, 1);
213     AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
214       sizeof(m_pLayout->mChannelLayoutTag), &m_pLayout->mChannelLayoutTag, &propSize, pLayout);
215   }
216
217   for (UInt32 c = 0; c < pLayout->mNumberChannelDescriptions; c++)
218   {
219     if (pLayout->mChannelDescriptions[c].mChannelLabel != kAudioChannelLabel_Unknown)
220     {
221       return false;
222     }
223   }
224
225   if (m_pLayout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions)
226     free(pLayout);
227
228   return true;
229 }
230