Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
2b7328b4
Commit
2b7328b4
authored
Jul 03, 2019
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
output/osx: fix coding style
parent
ca705e1e
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
137 additions
and
108 deletions
+137
-108
OSXOutputPlugin.cxx
src/output/plugins/OSXOutputPlugin.cxx
+137
-108
No files found.
src/output/plugins/OSXOutputPlugin.cxx
View file @
2b7328b4
...
@@ -45,18 +45,19 @@
...
@@ -45,18 +45,19 @@
static
constexpr
unsigned
MPD_OSX_BUFFER_TIME_MS
=
100
;
static
constexpr
unsigned
MPD_OSX_BUFFER_TIME_MS
=
100
;
static
StringBuffer
<
64
>
static
StringBuffer
<
64
>
StreamDescriptionToString
(
const
AudioStreamBasicDescription
desc
)
{
StreamDescriptionToString
(
const
AudioStreamBasicDescription
desc
)
{
// Only convert the lpcm formats (nothing else supported / used by MPD)
// Only convert the lpcm formats (nothing else supported / used by MPD)
assert
(
desc
.
mFormatID
==
kAudioFormatLinearPCM
);
assert
(
desc
.
mFormatID
==
kAudioFormatLinearPCM
);
return
StringFormat
<
64
>
(
"%u channel %s %sinterleaved %u-bit %s %s (%uHz)"
,
return
StringFormat
<
64
>
(
"%u channel %s %sinterleaved %u-bit %s %s (%uHz)"
,
desc
.
mChannelsPerFrame
,
desc
.
mChannelsPerFrame
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsNonMixable
)
?
""
:
"mixable"
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsNonMixable
)
?
""
:
"mixable"
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsNonInterleaved
)
?
"non-"
:
""
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsNonInterleaved
)
?
"non-"
:
""
,
desc
.
mBitsPerChannel
,
desc
.
mBitsPerChannel
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsFloat
)
?
"Float"
:
"SInt"
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsFloat
)
?
"Float"
:
"SInt"
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsBigEndian
)
?
"BE"
:
"LE"
,
(
desc
.
mFormatFlags
&
kAudioFormatFlagIsBigEndian
)
?
"BE"
:
"LE"
,
(
UInt32
)
desc
.
mSampleRate
);
(
UInt32
)
desc
.
mSampleRate
);
}
}
...
@@ -107,7 +108,8 @@ private:
...
@@ -107,7 +108,8 @@ private:
static
constexpr
Domain
osx_output_domain
(
"osx_output"
);
static
constexpr
Domain
osx_output_domain
(
"osx_output"
);
static
void
static
void
osx_os_status_to_cstring
(
OSStatus
status
,
char
*
str
,
size_t
size
)
{
osx_os_status_to_cstring
(
OSStatus
status
,
char
*
str
,
size_t
size
)
{
CFErrorRef
cferr
=
CFErrorCreate
(
nullptr
,
kCFErrorDomainOSStatus
,
status
,
nullptr
);
CFErrorRef
cferr
=
CFErrorCreate
(
nullptr
,
kCFErrorDomainOSStatus
,
status
,
nullptr
);
CFStringRef
cfstr
=
CFErrorCopyDescription
(
cferr
);
CFStringRef
cfstr
=
CFErrorCopyDescription
(
cferr
);
if
(
!
CFStringGetCString
(
cfstr
,
str
,
size
,
kCFStringEncodingUTF8
))
{
if
(
!
CFStringGetCString
(
cfstr
,
str
,
size
,
kCFStringEncodingUTF8
))
{
...
@@ -121,7 +123,7 @@ osx_os_status_to_cstring(OSStatus status, char *str, size_t size) {
...
@@ -121,7 +123,7 @@ osx_os_status_to_cstring(OSStatus status, char *str, size_t size) {
}
}
static
bool
static
bool
osx_output_test_default_device
(
void
)
osx_output_test_default_device
()
{
{
/* on a Mac, this is always the default plugin, if nothing
/* on a Mac, this is always the default plugin, if nothing
else is configured */
else is configured */
...
@@ -161,7 +163,7 @@ OSXOutput::Create(EventLoop &, const ConfigBlock &block)
...
@@ -161,7 +163,7 @@ OSXOutput::Create(EventLoop &, const ConfigBlock &block)
AudioObjectPropertyAddress
aopa
;
AudioObjectPropertyAddress
aopa
;
AudioDeviceID
dev_id
=
kAudioDeviceUnknown
;
AudioDeviceID
dev_id
=
kAudioDeviceUnknown
;
UInt32
dev_id_size
=
sizeof
(
dev_id
);
UInt32
dev_id_size
=
sizeof
(
dev_id
);
if
(
oo
->
component_subtype
==
kAudioUnitSubType_SystemOutput
)
if
(
oo
->
component_subtype
==
kAudioUnitSubType_SystemOutput
)
// get system output dev_id if configured
// get system output dev_id if configured
aopa
=
{
aopa
=
{
...
@@ -170,7 +172,8 @@ OSXOutput::Create(EventLoop &, const ConfigBlock &block)
...
@@ -170,7 +172,8 @@ OSXOutput::Create(EventLoop &, const ConfigBlock &block)
kAudioObjectPropertyElementMaster
kAudioObjectPropertyElementMaster
};
};
else
else
// fallback to default device initially (can still be changed by osx_output_set_device)
/* fallback to default device initially (can still be
changed by osx_output_set_device) */
aopa
=
{
aopa
=
{
kAudioHardwarePropertyDefaultOutputDevice
,
kAudioHardwarePropertyDefaultOutputDevice
,
kAudioObjectPropertyScopeOutput
,
kAudioObjectPropertyScopeOutput
,
...
@@ -216,7 +219,8 @@ OSXOutput::GetVolume()
...
@@ -216,7 +219,8 @@ OSXOutput::GetVolume()
}
}
void
void
OSXOutput
::
SetVolume
(
unsigned
new_volume
)
{
OSXOutput
::
SetVolume
(
unsigned
new_volume
)
{
Float32
vol
=
new_volume
/
100.0
;
Float32
vol
=
new_volume
/
100.0
;
AudioObjectPropertyAddress
aopa
=
{
AudioObjectPropertyAddress
aopa
=
{
.
mSelector
=
kAudioHardwareServiceDeviceProperty_VirtualMasterVolume
,
.
mSelector
=
kAudioHardwareServiceDeviceProperty_VirtualMasterVolume
,
...
@@ -240,11 +244,10 @@ OSXOutput::SetVolume(unsigned new_volume) {
...
@@ -240,11 +244,10 @@ OSXOutput::SetVolume(unsigned new_volume) {
}
}
static
void
static
void
osx_output_parse_channel_map
(
osx_output_parse_channel_map
(
const
char
*
device_name
,
const
char
*
device_name
,
const
char
*
channel_map_str
,
const
char
*
channel_map_str
,
SInt32
channel_map
[],
SInt32
channel_map
[],
UInt32
num_channels
)
UInt32
num_channels
)
{
{
char
*
endptr
;
char
*
endptr
;
unsigned
int
inserted_channels
=
0
;
unsigned
int
inserted_channels
=
0
;
...
@@ -331,7 +334,8 @@ osx_output_set_channel_map(OSXOutput *oo)
...
@@ -331,7 +334,8 @@ osx_output_set_channel_map(OSXOutput *oo)
static
float
static
float
osx_output_score_sample_rate
(
Float64
destination_rate
,
unsigned
int
source_rate
)
{
osx_output_score_sample_rate
(
Float64
destination_rate
,
unsigned
source_rate
)
{
float
score
=
0
;
float
score
=
0
;
double
int_portion
;
double
int_portion
;
double
frac_portion
=
modf
(
source_rate
/
destination_rate
,
&
int_portion
);
double
frac_portion
=
modf
(
source_rate
/
destination_rate
,
&
int_portion
);
...
@@ -341,24 +345,27 @@ osx_output_score_sample_rate(Float64 destination_rate, unsigned int source_rate)
...
@@ -341,24 +345,27 @@ osx_output_score_sample_rate(Float64 destination_rate, unsigned int source_rate)
score
+=
(
int_portion
==
1.0
)
?
500
:
0
;
score
+=
(
int_portion
==
1.0
)
?
500
:
0
;
if
(
source_rate
==
destination_rate
)
if
(
source_rate
==
destination_rate
)
score
+=
1000
;
score
+=
1000
;
else
if
(
source_rate
>
destination_rate
)
else
if
(
source_rate
>
destination_rate
)
score
+=
(
int_portion
>
1
&&
int_portion
<
100
)
?
(
100
-
int_portion
)
/
100
*
100
:
0
;
score
+=
(
int_portion
>
1
&&
int_portion
<
100
)
?
(
100
-
int_portion
)
/
100
*
100
:
0
;
else
else
score
+=
(
int_portion
>
1
&&
int_portion
<
100
)
?
(
100
+
int_portion
)
/
100
*
100
:
0
;
score
+=
(
int_portion
>
1
&&
int_portion
<
100
)
?
(
100
+
int_portion
)
/
100
*
100
:
0
;
return
score
;
return
score
;
}
}
static
float
static
float
osx_output_score_format
(
const
AudioStreamBasicDescription
&
format_desc
,
const
AudioStreamBasicDescription
&
target_format
)
{
osx_output_score_format
(
const
AudioStreamBasicDescription
&
format_desc
,
const
AudioStreamBasicDescription
&
target_format
)
{
float
score
=
0
;
float
score
=
0
;
// Score only linear PCM formats (everything else MPD cannot use)
// Score only linear PCM formats (everything else MPD cannot use)
if
(
format_desc
.
mFormatID
==
kAudioFormatLinearPCM
)
{
if
(
format_desc
.
mFormatID
==
kAudioFormatLinearPCM
)
{
score
+=
osx_output_score_sample_rate
(
format_desc
.
mSampleRate
,
target_format
.
mSampleRate
);
score
+=
osx_output_score_sample_rate
(
format_desc
.
mSampleRate
,
target_format
.
mSampleRate
);
// Just choose the stream / format with the highest number of output channels
// Just choose the stream / format with the highest number of output channels
score
+=
format_desc
.
mChannelsPerFrame
*
5
;
score
+=
format_desc
.
mChannelsPerFrame
*
5
;
if
(
target_format
.
mFormatFlags
==
kLinearPCMFormatFlagIsFloat
)
{
if
(
target_format
.
mFormatFlags
==
kLinearPCMFormatFlagIsFloat
)
{
// for float, prefer the highest bitdepth we have
// for float, prefer the highest bitdepth we have
if
(
format_desc
.
mBitsPerChannel
>=
16
)
if
(
format_desc
.
mBitsPerChannel
>=
16
)
...
@@ -368,14 +375,16 @@ osx_output_score_format(const AudioStreamBasicDescription &format_desc, const Au
...
@@ -368,14 +375,16 @@ osx_output_score_format(const AudioStreamBasicDescription &format_desc, const Au
score
+=
5
;
score
+=
5
;
else
if
(
format_desc
.
mBitsPerChannel
>
target_format
.
mBitsPerChannel
)
else
if
(
format_desc
.
mBitsPerChannel
>
target_format
.
mBitsPerChannel
)
score
+=
1
;
score
+=
1
;
}
}
}
}
return
score
;
return
score
;
}
}
static
Float64
static
Float64
osx_output_set_device_format
(
AudioDeviceID
dev_id
,
const
AudioStreamBasicDescription
&
target_format
)
osx_output_set_device_format
(
AudioDeviceID
dev_id
,
const
AudioStreamBasicDescription
&
target_format
)
{
{
AudioObjectPropertyAddress
aopa
=
{
AudioObjectPropertyAddress
aopa
=
{
kAudioDevicePropertyStreams
,
kAudioDevicePropertyStreams
,
...
@@ -384,66 +393,69 @@ osx_output_set_device_format(AudioDeviceID dev_id, const AudioStreamBasicDescrip
...
@@ -384,66 +393,69 @@ osx_output_set_device_format(AudioDeviceID dev_id, const AudioStreamBasicDescrip
};
};
UInt32
property_size
;
UInt32
property_size
;
OSStatus
err
=
AudioObjectGetPropertyDataSize
(
dev_id
,
&
aopa
,
0
,
NULL
,
&
property_size
);
OSStatus
err
=
AudioObjectGetPropertyDataSize
(
dev_id
,
&
aopa
,
0
,
NULL
,
&
property_size
);
if
(
err
!=
noErr
)
{
if
(
err
!=
noErr
)
throw
FormatRuntimeError
(
"Cannot get number of streams: %d
\n
"
,
err
);
throw
FormatRuntimeError
(
"Cannot get number of streams: %d
\n
"
,
err
);
}
int
n_streams
=
property_size
/
sizeof
(
AudioStreamID
);
int
n_streams
=
property_size
/
sizeof
(
AudioStreamID
);
AudioStreamID
streams
[
n_streams
];
AudioStreamID
streams
[
n_streams
];
err
=
AudioObjectGetPropertyData
(
dev_id
,
&
aopa
,
0
,
NULL
,
&
property_size
,
streams
);
err
=
AudioObjectGetPropertyData
(
dev_id
,
&
aopa
,
0
,
NULL
,
&
property_size
,
streams
);
if
(
err
!=
noErr
)
if
(
err
!=
noErr
)
{
throw
FormatRuntimeError
(
"Cannot get streams: %d
\n
"
,
err
);
throw
FormatRuntimeError
(
"Cannot get streams: %d
\n
"
,
err
);
}
bool
format_found
=
false
;
bool
format_found
=
false
;
int
output_stream
;
int
output_stream
;
AudioStreamBasicDescription
output_format
;
AudioStreamBasicDescription
output_format
;
for
(
int
i
=
0
;
i
<
n_streams
;
i
++
)
{
for
(
int
i
=
0
;
i
<
n_streams
;
i
++
)
{
UInt32
direction
;
UInt32
direction
;
AudioStreamID
stream
=
streams
[
i
];
AudioStreamID
stream
=
streams
[
i
];
aopa
.
mSelector
=
kAudioStreamPropertyDirection
;
aopa
.
mSelector
=
kAudioStreamPropertyDirection
;
property_size
=
sizeof
(
direction
);
property_size
=
sizeof
(
direction
);
err
=
AudioObjectGetPropertyData
(
stream
,
err
=
AudioObjectGetPropertyData
(
stream
,
&
aopa
,
&
aopa
,
0
,
0
,
NULL
,
NULL
,
&
property_size
,
&
property_size
,
&
direction
);
&
direction
);
if
(
err
!=
noErr
)
{
if
(
err
!=
noErr
)
throw
FormatRuntimeError
(
"Cannot get streams direction: %d
\n
"
,
err
);
throw
FormatRuntimeError
(
"Cannot get streams direction: %d
\n
"
,
}
err
);
if
(
direction
!=
0
)
{
if
(
direction
!=
0
)
continue
;
continue
;
}
aopa
.
mSelector
=
kAudioStreamPropertyAvailablePhysicalFormats
;
aopa
.
mSelector
=
kAudioStreamPropertyAvailablePhysicalFormats
;
err
=
AudioObjectGetPropertyDataSize
(
stream
,
&
aopa
,
0
,
NULL
,
&
property_size
);
err
=
AudioObjectGetPropertyDataSize
(
stream
,
&
aopa
,
0
,
NULL
,
&
property_size
);
if
(
err
!=
noErr
)
if
(
err
!=
noErr
)
throw
FormatRuntimeError
(
"Unable to get format size s for stream %d. Error = %s"
,
streams
[
i
],
err
);
throw
FormatRuntimeError
(
"Unable to get format size s for stream %d. Error = %s"
,
streams
[
i
],
err
);
in
t
format_count
=
property_size
/
sizeof
(
AudioStreamRangedDescription
);
const
size_
t
format_count
=
property_size
/
sizeof
(
AudioStreamRangedDescription
);
AudioStreamRangedDescription
format_list
[
format_count
];
AudioStreamRangedDescription
format_list
[
format_count
];
err
=
AudioObjectGetPropertyData
(
stream
,
&
aopa
,
0
,
NULL
,
&
property_size
,
format_list
);
err
=
AudioObjectGetPropertyData
(
stream
,
&
aopa
,
0
,
NULL
,
&
property_size
,
format_list
);
if
(
err
!=
noErr
)
if
(
err
!=
noErr
)
throw
FormatRuntimeError
(
"Unable to get available formats for stream %d. Error = %s"
,
streams
[
i
],
err
);
throw
FormatRuntimeError
(
"Unable to get available formats for stream %d. Error = %s"
,
streams
[
i
],
err
);
float
output_score
=
0
;
float
output_score
=
0
;
for
(
in
t
j
=
0
;
j
<
format_count
;
j
++
)
{
for
(
size_
t
j
=
0
;
j
<
format_count
;
j
++
)
{
AudioStreamBasicDescription
format_desc
=
format_list
[
j
].
mFormat
;
AudioStreamBasicDescription
format_desc
=
format_list
[
j
].
mFormat
;
std
::
string
format_string
;
std
::
string
format_string
;
// for devices with kAudioStreamAnyRate
// for devices with kAudioStreamAnyRate
// we use the requested samplerate here
// we use the requested samplerate here
if
(
format_desc
.
mSampleRate
==
kAudioStreamAnyRate
)
if
(
format_desc
.
mSampleRate
==
kAudioStreamAnyRate
)
format_desc
.
mSampleRate
=
target_format
.
mSampleRate
;
format_desc
.
mSampleRate
=
target_format
.
mSampleRate
;
float
score
=
osx_output_score_format
(
format_desc
,
target_format
);
float
score
=
osx_output_score_format
(
format_desc
,
target_format
);
// print all (linear pcm) formats and their rating
// print all (linear pcm) formats and their rating
if
(
score
>
0.0
)
if
(
score
>
0.0
)
FormatDebug
(
osx_output_domain
,
"Format: %s rated %f"
,
StreamDescriptionToString
(
format_desc
).
c_str
(),
score
);
FormatDebug
(
osx_output_domain
,
"Format: %s rated %f"
,
StreamDescriptionToString
(
format_desc
).
c_str
(),
score
);
if
(
score
>
output_score
)
{
if
(
score
>
output_score
)
{
output_score
=
score
;
output_score
=
score
;
output_format
=
format_desc
;
output_format
=
format_desc
;
...
@@ -454,23 +466,24 @@ osx_output_set_device_format(AudioDeviceID dev_id, const AudioStreamBasicDescrip
...
@@ -454,23 +466,24 @@ osx_output_set_device_format(AudioDeviceID dev_id, const AudioStreamBasicDescrip
}
}
if
(
format_found
)
{
if
(
format_found
)
{
aopa
.
mSelector
=
kAudioStreamPropertyPhysicalFormat
;
aopa
.
mSelector
=
kAudioStreamPropertyPhysicalFormat
;
err
=
AudioObjectSetPropertyData
(
output_stream
,
err
=
AudioObjectSetPropertyData
(
output_stream
,
&
aopa
,
&
aopa
,
0
,
0
,
NULL
,
NULL
,
sizeof
(
output_format
),
sizeof
(
output_format
),
&
output_format
);
&
output_format
);
if
(
err
!=
noErr
)
{
if
(
err
!=
noErr
)
throw
FormatRuntimeError
(
"Failed to change the stream format: %d
\n
"
,
err
);
throw
FormatRuntimeError
(
"Failed to change the stream format: %d
\n
"
,
}
err
);
}
}
return
output_format
.
mSampleRate
;
return
output_format
.
mSampleRate
;
}
}
static
OSStatus
static
OSStatus
osx_output_set_buffer_size
(
AudioUnit
au
,
AudioStreamBasicDescription
desc
,
UInt32
*
frame_size
)
osx_output_set_buffer_size
(
AudioUnit
au
,
AudioStreamBasicDescription
desc
,
UInt32
*
frame_size
)
{
{
AudioValueRange
value_range
=
{
0
,
0
};
AudioValueRange
value_range
=
{
0
,
0
};
UInt32
property_size
=
sizeof
(
AudioValueRange
);
UInt32
property_size
=
sizeof
(
AudioValueRange
);
...
@@ -491,7 +504,7 @@ osx_output_set_buffer_size(AudioUnit au, AudioStreamBasicDescription desc, UInt3
...
@@ -491,7 +504,7 @@ osx_output_set_buffer_size(AudioUnit au, AudioStreamBasicDescription desc, UInt3
&
buffer_frame_size
,
&
buffer_frame_size
,
sizeof
(
buffer_frame_size
));
sizeof
(
buffer_frame_size
));
if
(
err
!=
noErr
)
if
(
err
!=
noErr
)
FormatWarning
(
osx_output_domain
,
FormatWarning
(
osx_output_domain
,
"Failed to set maximum buffer size: %d"
,
"Failed to set maximum buffer size: %d"
,
err
);
err
);
...
@@ -503,7 +516,7 @@ osx_output_set_buffer_size(AudioUnit au, AudioStreamBasicDescription desc, UInt3
...
@@ -503,7 +516,7 @@ osx_output_set_buffer_size(AudioUnit au, AudioStreamBasicDescription desc, UInt3
&
buffer_frame_size
,
&
buffer_frame_size
,
&
property_size
);
&
property_size
);
if
(
err
!=
noErr
)
{
if
(
err
!=
noErr
)
{
FormatWarning
(
osx_output_domain
,
FormatWarning
(
osx_output_domain
,
"Cannot get the buffer frame size: %d"
,
"Cannot get the buffer frame size: %d"
,
err
);
err
);
return
err
;
return
err
;
...
@@ -542,19 +555,21 @@ osx_output_hog_device(AudioDeviceID dev_id, bool hog)
...
@@ -542,19 +555,21 @@ osx_output_hog_device(AudioDeviceID dev_id, bool hog)
err
);
err
);
return
;
return
;
}
}
if
(
hog
)
{
if
(
hog
)
{
if
(
hog_pid
!=
-
1
)
{
if
(
hog_pid
!=
-
1
)
{
FormatDebug
(
osx_output_domain
,
FormatDebug
(
osx_output_domain
,
"Device is already hogged."
);
"Device is already hogged."
);
return
;
return
;
}
}
}
else
{
}
else
{
if
(
hog_pid
!=
getpid
())
{
if
(
hog_pid
!=
getpid
())
{
FormatDebug
(
osx_output_domain
,
FormatDebug
(
osx_output_domain
,
"Device is not owned by this process."
);
"Device is not owned by this process."
);
return
;
return
;
}
}
}
}
hog_pid
=
hog
?
getpid
()
:
-
1
;
hog_pid
=
hog
?
getpid
()
:
-
1
;
size
=
sizeof
(
hog_pid
);
size
=
sizeof
(
hog_pid
);
err
=
AudioObjectSetPropertyData
(
dev_id
,
err
=
AudioObjectSetPropertyData
(
dev_id
,
...
@@ -568,9 +583,10 @@ osx_output_hog_device(AudioDeviceID dev_id, bool hog)
...
@@ -568,9 +583,10 @@ osx_output_hog_device(AudioDeviceID dev_id, bool hog)
"Cannot hog the device: %d"
,
"Cannot hog the device: %d"
,
err
);
err
);
}
else
{
}
else
{
FormatDebug
(
osx_output_domain
,
LogDebug
(
osx_output_domain
,
hog_pid
==
-
1
?
"Device is unhogged"
hog_pid
==
-
1
:
"Device is hogged"
);
?
"Device is unhogged"
:
"Device is hogged"
);
}
}
}
}
...
@@ -595,8 +611,11 @@ osx_output_set_device(OSXOutput *oo)
...
@@ -595,8 +611,11 @@ osx_output_set_device(OSXOutput *oo)
return
;
return
;
/* how many audio devices are there? */
/* how many audio devices are there? */
propaddr
=
{
kAudioHardwarePropertyDevices
,
kAudioObjectPropertyScopeGlobal
,
kAudioObjectPropertyElementMaster
};
propaddr
=
{
kAudioHardwarePropertyDevices
,
status
=
AudioObjectGetPropertyDataSize
(
kAudioObjectSystemObject
,
&
propaddr
,
0
,
nullptr
,
&
size
);
kAudioObjectPropertyScopeGlobal
,
kAudioObjectPropertyElementMaster
};
status
=
AudioObjectGetPropertyDataSize
(
kAudioObjectSystemObject
,
&
propaddr
,
0
,
nullptr
,
&
size
);
if
(
status
!=
noErr
)
{
if
(
status
!=
noErr
)
{
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
throw
FormatRuntimeError
(
"Unable to determine number of OS X audio devices: %s"
,
throw
FormatRuntimeError
(
"Unable to determine number of OS X audio devices: %s"
,
...
@@ -606,7 +625,9 @@ osx_output_set_device(OSXOutput *oo)
...
@@ -606,7 +625,9 @@ osx_output_set_device(OSXOutput *oo)
/* what are the available audio device IDs? */
/* what are the available audio device IDs? */
numdevices
=
size
/
sizeof
(
AudioDeviceID
);
numdevices
=
size
/
sizeof
(
AudioDeviceID
);
std
::
unique_ptr
<
AudioDeviceID
[]
>
deviceids
(
new
AudioDeviceID
[
numdevices
]);
std
::
unique_ptr
<
AudioDeviceID
[]
>
deviceids
(
new
AudioDeviceID
[
numdevices
]);
status
=
AudioObjectGetPropertyData
(
kAudioObjectSystemObject
,
&
propaddr
,
0
,
nullptr
,
&
size
,
deviceids
.
get
());
status
=
AudioObjectGetPropertyData
(
kAudioObjectSystemObject
,
&
propaddr
,
0
,
nullptr
,
&
size
,
deviceids
.
get
());
if
(
status
!=
noErr
)
{
if
(
status
!=
noErr
)
{
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
throw
FormatRuntimeError
(
"Unable to determine OS X audio device IDs: %s"
,
throw
FormatRuntimeError
(
"Unable to determine OS X audio device IDs: %s"
,
...
@@ -614,10 +635,14 @@ osx_output_set_device(OSXOutput *oo)
...
@@ -614,10 +635,14 @@ osx_output_set_device(OSXOutput *oo)
}
}
/* which audio device matches oo->device_name? */
/* which audio device matches oo->device_name? */
propaddr
=
{
kAudioObjectPropertyName
,
kAudioObjectPropertyScopeGlobal
,
kAudioObjectPropertyElementMaster
};
propaddr
=
{
kAudioObjectPropertyName
,
kAudioObjectPropertyScopeGlobal
,
kAudioObjectPropertyElementMaster
};
size
=
sizeof
(
CFStringRef
);
size
=
sizeof
(
CFStringRef
);
for
(
i
=
0
;
i
<
numdevices
;
i
++
)
{
for
(
i
=
0
;
i
<
numdevices
;
i
++
)
{
status
=
AudioObjectGetPropertyData
(
deviceids
[
i
],
&
propaddr
,
0
,
nullptr
,
&
size
,
&
cfname
);
status
=
AudioObjectGetPropertyData
(
deviceids
[
i
],
&
propaddr
,
0
,
nullptr
,
&
size
,
&
cfname
);
if
(
status
!=
noErr
)
{
if
(
status
!=
noErr
)
{
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
throw
FormatRuntimeError
(
"Unable to determine OS X device name "
throw
FormatRuntimeError
(
"Unable to determine OS X device name "
...
@@ -626,7 +651,8 @@ osx_output_set_device(OSXOutput *oo)
...
@@ -626,7 +651,8 @@ osx_output_set_device(OSXOutput *oo)
errormsg
);
errormsg
);
}
}
if
(
!
CFStringGetCString
(
cfname
,
name
,
sizeof
(
name
),
kCFStringEncodingUTF8
))
if
(
!
CFStringGetCString
(
cfname
,
name
,
sizeof
(
name
),
kCFStringEncodingUTF8
))
throw
std
::
runtime_error
(
"Unable to convert device name from CFStringRef to char*"
);
throw
std
::
runtime_error
(
"Unable to convert device name from CFStringRef to char*"
);
if
(
strcmp
(
oo
->
device_name
,
name
)
==
0
)
{
if
(
strcmp
(
oo
->
device_name
,
name
)
==
0
)
{
...
@@ -636,10 +662,10 @@ osx_output_set_device(OSXOutput *oo)
...
@@ -636,10 +662,10 @@ osx_output_set_device(OSXOutput *oo)
break
;
break
;
}
}
}
}
if
(
i
==
numdevices
)
{
throw
FormatRuntimeError
(
"Found no audio device with name '%s' "
,
if
(
i
==
numdevices
)
throw
FormatRuntimeError
(
"Found no audio device with name '%s' "
,
oo
->
device_name
);
oo
->
device_name
);
}
status
=
AudioUnitSetProperty
(
oo
->
au
,
status
=
AudioUnitSetProperty
(
oo
->
au
,
kAudioOutputUnitProperty_CurrentDevice
,
kAudioOutputUnitProperty_CurrentDevice
,
...
@@ -663,13 +689,13 @@ osx_output_set_device(OSXOutput *oo)
...
@@ -663,13 +689,13 @@ osx_output_set_device(OSXOutput *oo)
}
}
/*
/*
*
This function (the 'render callback' osx_render) is called by the
*
This function (the 'render callback' osx_render) is called by the
OS X audio subsystem (CoreAudio) to request audio data that will be
*
OS X audio subsystem (CoreAudio) to request audio data that will be
played by the audio hardware. This function has hard time constraints
* played by the audio hardware. This function has hard time
so it cannot do IO (debug statements) or memory allocations.
* constraints so it cannot do IO (debug statements) or memory
*/
* allocations.
*/
static
OSStatus
static
OSStatus
osx_render
(
void
*
vdata
,
osx_render
(
void
*
vdata
,
gcc_unused
AudioUnitRenderActionFlags
*
io_action_flags
,
gcc_unused
AudioUnitRenderActionFlags
*
io_action_flags
,
...
@@ -684,7 +710,7 @@ osx_render(void *vdata,
...
@@ -684,7 +710,7 @@ osx_render(void *vdata,
buffer_list
->
mBuffers
[
0
].
mDataByteSize
=
buffer_list
->
mBuffers
[
0
].
mDataByteSize
=
od
->
ring_buffer
->
pop
((
uint8_t
*
)
buffer_list
->
mBuffers
[
0
].
mData
,
od
->
ring_buffer
->
pop
((
uint8_t
*
)
buffer_list
->
mBuffers
[
0
].
mData
,
count
);
count
);
return
noErr
;
return
noErr
;
}
}
void
void
...
@@ -722,7 +748,7 @@ OSXOutput::Enable()
...
@@ -722,7 +748,7 @@ OSXOutput::Enable()
#endif
#endif
throw
;
throw
;
}
}
if
(
hog_device
)
if
(
hog_device
)
osx_output_hog_device
(
dev_id
,
true
);
osx_output_hog_device
(
dev_id
,
true
);
}
}
...
@@ -794,7 +820,9 @@ OSXOutput::Open(AudioFormat &audio_format)
...
@@ -794,7 +820,9 @@ OSXOutput::Open(AudioFormat &audio_format)
Float64
sample_rate
=
osx_output_set_device_format
(
dev_id
,
asbd
);
Float64
sample_rate
=
osx_output_set_device_format
(
dev_id
,
asbd
);
#ifdef ENABLE_DSD
#ifdef ENABLE_DSD
if
(
audio_format
.
format
==
SampleFormat
::
DSD
&&
sample_rate
!=
asbd
.
mSampleRate
)
{
// fall back to PCM in case sample_rate cannot be synchronized
if
(
audio_format
.
format
==
SampleFormat
::
DSD
&&
sample_rate
!=
asbd
.
mSampleRate
)
{
// fall back to PCM in case sample_rate cannot be synchronized
params
.
dop
=
false
;
params
.
dop
=
false
;
audio_format
.
format
=
SampleFormat
::
S32
;
audio_format
.
format
=
SampleFormat
::
S32
;
asbd
.
mBitsPerChannel
=
32
;
asbd
.
mBitsPerChannel
=
32
;
...
@@ -846,7 +874,7 @@ OSXOutput::Open(AudioFormat &audio_format)
...
@@ -846,7 +874,7 @@ OSXOutput::Open(AudioFormat &audio_format)
MPD_OSX_BUFFER_TIME_MS
*
audio_format
.
GetFrameSize
()
*
audio_format
.
sample_rate
/
1000
);
MPD_OSX_BUFFER_TIME_MS
*
audio_format
.
GetFrameSize
()
*
audio_format
.
sample_rate
/
1000
);
#ifdef ENABLE_DSD
#ifdef ENABLE_DSD
if
(
dop_enabled
)
{
if
(
dop_enabled
)
{
pcm_export
->
Open
(
audio_format
.
format
,
audio_format
.
channels
,
params
);
pcm_export
->
Open
(
audio_format
.
format
,
audio_format
.
channels
,
params
);
ring_buffer_size
=
std
::
max
<
size_t
>
(
buffer_frame_size
,
ring_buffer_size
=
std
::
max
<
size_t
>
(
buffer_frame_size
,
MPD_OSX_BUFFER_TIME_MS
*
pcm_export
->
GetFrameSize
(
audio_format
)
*
asbd
.
mSampleRate
/
1000
);
MPD_OSX_BUFFER_TIME_MS
*
pcm_export
->
GetFrameSize
(
audio_format
)
*
asbd
.
mSampleRate
/
1000
);
...
@@ -868,7 +896,7 @@ size_t
...
@@ -868,7 +896,7 @@ size_t
OSXOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
OSXOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
{
assert
(
size
>
0
);
assert
(
size
>
0
);
if
(
pause
)
{
if
(
pause
)
{
pause
=
false
;
pause
=
false
;
OSStatus
status
=
AudioOutputUnitStart
(
au
);
OSStatus
status
=
AudioOutputUnitStart
(
au
);
if
(
status
!=
0
)
{
if
(
status
!=
0
)
{
...
@@ -877,7 +905,7 @@ OSXOutput::Play(const void *chunk, size_t size)
...
@@ -877,7 +905,7 @@ OSXOutput::Play(const void *chunk, size_t size)
}
}
}
}
#ifdef ENABLE_DSD
#ifdef ENABLE_DSD
if
(
dop_enabled
)
{
if
(
dop_enabled
)
{
const
auto
e
=
pcm_export
->
Export
({
chunk
,
size
});
const
auto
e
=
pcm_export
->
Export
({
chunk
,
size
});
/* the DoP (DSD over PCM) filter converts two frames
/* the DoP (DSD over PCM) filter converts two frames
at a time and ignores the last odd frame; if there
at a time and ignores the last odd frame; if there
...
@@ -902,9 +930,10 @@ OSXOutput::Delay() const noexcept
...
@@ -902,9 +930,10 @@ OSXOutput::Delay() const noexcept
?
std
::
chrono
::
steady_clock
::
duration
::
zero
()
?
std
::
chrono
::
steady_clock
::
duration
::
zero
()
:
std
::
chrono
::
milliseconds
(
MPD_OSX_BUFFER_TIME_MS
/
4
);
:
std
::
chrono
::
milliseconds
(
MPD_OSX_BUFFER_TIME_MS
/
4
);
}
}
bool
OSXOutput
::
Pause
()
{
bool
OSXOutput
::
Pause
()
if
(
!
pause
)
{
{
if
(
!
pause
)
{
pause
=
true
;
pause
=
true
;
AudioOutputUnitStop
(
au
);
AudioOutputUnitStop
(
au
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment