/* * Strawberry Music Player * This file was part of Clementine. * Copyright 2014, David Sansome * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Strawberry is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Strawberry. If not, see . * */ #include "config.h" #include #include #include "osxdevicefinder.h" #include "core/logging.h" #include "core/scoped_cftyperef.h" namespace { template std::unique_ptr GetProperty(const AudioDeviceID& device_id, const AudioObjectPropertyAddress& address, UInt32* size_bytes_out = nullptr) { UInt32 size_bytes = 0; OSStatus status = AudioObjectGetPropertyDataSize(device_id, &address, 0, NULL, &size_bytes); if (status != kAudioHardwareNoError) { qLog(Warning) << "AudioObjectGetPropertyDataSize failed:" << status; return std::unique_ptr(); } std::unique_ptr ret(reinterpret_cast(malloc(size_bytes))); status = AudioObjectGetPropertyData(device_id, &address, 0, NULL, &size_bytes, ret.get()); if (status != kAudioHardwareNoError) { qLog(Warning) << "AudioObjectGetPropertyData failed:" << status; return std::unique_ptr(); } if (size_bytes_out) { *size_bytes_out = size_bytes; } return ret; } } // namespace OsxDeviceFinder::OsxDeviceFinder() : DeviceFinder("osxaudiosink") { } QList OsxDeviceFinder::ListDevices() { QList ret; AudioObjectPropertyAddress address = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; UInt32 device_size_bytes = 0; std::unique_ptr devices = GetProperty(kAudioObjectSystemObject, address, &device_size_bytes); if (!devices.get()) { return ret; } const int device_count = device_size_bytes / sizeof(AudioDeviceID); address.mScope = kAudioDevicePropertyScopeOutput; for (UInt32 i = 0; i < device_count; ++i) { const AudioDeviceID id = devices.get()[i]; // Query device name address.mSelector = kAudioDevicePropertyDeviceNameCFString; std::unique_ptr device_name = GetProperty(id, address); ScopedCFTypeRef scoped_device_name(*device_name.get()); if (!device_name.get()) { continue; } // Determine if the device is an output device (it is an output device if // it has output channels) address.mSelector = kAudioDevicePropertyStreamConfiguration; std::unique_ptr buffer_list = GetProperty(id, address); if (!buffer_list.get() || buffer_list->mNumberBuffers == 0) { continue; } Device dev; dev.description = QString::fromUtf8(CFStringGetCStringPtr(*device_name, CFStringGetSystemEncoding())); dev.value = id; dev.iconname = GuessIconName(dev.description); ret.append(dev); } return ret; }