gen2brain / malgo

Mini audio library
The Unlicense
288 stars 49 forks source link

Q: Why is iOS not supported? #25

Closed fdraxler closed 4 months ago

fdraxler commented 3 years ago

malgo does not list iOS as a supported platform, but macOS. As far as I understand, Miniaudio is based on Core Audio for both macOS and iOS. So I am surprised by this restriction. Is this a hard constraint, i.e. is there a technical burden that prohibits deployment, or is it just not tested?

Many thanks for an answer to help me out!

gen2brain commented 3 years ago

"The macOS build should compile cleanly without the need to download any dependencies nor link to any libraries or frameworks. The iOS build needs to be compiled as Objective-C and will need to link the relevant frameworks but should compile cleanly out of the box with Xcode."

This is from miniaudio header file. I know there is support for .m files in Go cgo, so probably it just needs a wrapper with build tags just for iOS. I never used iOS and never compiled anything for it, the macOS build I can test in VM but never tried the iOS simulator etc.

fdraxler commented 3 years ago

Many thanks for your quick and helpful answer! I will try and report back here, maybe with a PR or build instructions :)

sugarme commented 4 months ago

@fdraxler ,

Any update?

@gen2brain ,

Could you give further detail about " just needs a wrapper with build tags just for iOS." please?

gen2brain commented 4 months ago

@sugarme Not sure if there is a need to have a new .m file similar to https://github.com/gen2brain/malgo/blob/master/miniaudio.c#L3, or if the same C file can be compiled as objective-c. If a new file is needed it should be named miniaudio_ios.m, and it also needs required frameworks in LDFLAGS, if any (not sure if the miniaudio also uses runtime linking on iOS).

Doesn't seem like too much work, but I only have macOS in VM, I would probably need a simulator and what not, and it looks hard to do anything without IDE.

sugarme commented 4 months ago

@gen2brain, Thanks for the response. What should be in the .m file? Any draft would be great. I tried to use malgo with fyne and cross-compile failed with errors like

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSZone.h:19:63: error: unknown type name 'NSString'; did you mean 'GoString'?

I tried to hard code miniaudio.go by adding some more flags:

// Package malgo - Mini audio library (miniaudio cgo bindings).
package malgo

/*
#cgo CFLAGS: -std=gnu99 -Wno-unused-result
#cgo ma_debug CFLAGS: -DMA_DEBUG_OUTPUT=1

#cgo linux,!android LDFLAGS: -ldl -lpthread -lm
#cgo linux,arm LDFLAGS: -latomic
#cgo openbsd LDFLAGS: -ldl -lpthread -lm
#cgo netbsd LDFLAGS: -ldl -lpthread -lm
#cgo freebsd LDFLAGS: -ldl -lpthread -lm
#cgo android LDFLAGS: -lm

#cgo !noasm,!arm,!arm64 CFLAGS: -msse2
#cgo !noasm,arm,arm64 CFLAGS: -mfpu=neon -mfloat-abi=hard
#cgo noasm CFLAGS: -DMA_NO_SSE2 -DMA_NO_AVX2 -DMA_NO_AVX512 -DMA_NO_NEON

// Newly added:
//===========
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#cgo LDFLAGS: -framework AudioUnit -framework CoreAudio -framework AudioToolbox
#import <Foundation/Foundation.h>

#include "malgo.h"
*/
import "C"

// SampleSizeInBytes retrieves the size of a sample in bytes for the given format.
func SampleSizeInBytes(format FormatType) int {
    cformat := (C.ma_format)(format)
    ret := C.ma_get_bytes_per_sample(cformat)
    return int(ret)
}

const (
    rawDeviceInfoSize = C.sizeof_ma_device_info
)

but didn't work. There were heaps of errors. Some like:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLSession.h:1441:1: error: expected identifier or '('
@end
^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLSession.h:1457:1: error: expected identifier or '('
@property (copy, readonly) NSDateInterval *taskInterval;
^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLSession.h:1462:1: error: expected identifier or '('
@property (assign, readonly) NSUInteger redirectCount;
^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLSession.h:1465:1: error: expected external declaration
- (instancetype)init API_DEPRECATED("Not supported", macos(10.12,10.15), ios(10.0,13.0), watchos(3.0,6.0), tvos(10.0,13.0));
^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLSession.h:1465:4: error: redefinition of 'id' as different kind of symbol
- (instancetype)init API_DEPRECATED("Not supported", macos(10.12,10.15), ios(10.0,13.0), watchos(3.0,6.0), tvos(10.0,13.0));
   ^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:231:22: note: expanded from macro 'instancetype'
#define instancetype id
                     ^

Hope you can point me to the right direction. Thanks.

gen2brain commented 4 months ago

Well, perhaps it doesn't need new file and all it needs is something like this:

#cgo ios CFLAGS: -x objective-c
#cgo ios LDFLAGS: -framework CoreFoundation -framework CoreAudio -framework AudioUnit

Again, not sure if there is a need for frameworks or not, and if that is the correct way to start.

sugarme commented 4 months ago

@gen2brain,

with those line, I got some warning and an error of linking AudioUnit

fyne package -os ios -appID medpod.io -icon Icon.png
go build -tags ios -ldflags=-w -o=/var/folders/ml/58bpg4t555ldbfmthkbnvlq00000gp/T/fyne-work-3969837344/arm64 github.com/sugarme/medpod-app failed: exit status 1
# fyne.io/fyne/v2/internal/driver/mobile/app
darwin_ios.m:51:18: warning: assigning to 'id<UNUserNotificationCenterDelegate> _Nullable' from incompatible type 'GoAppAppDelegate *'
darwin_ios.m:213:19: warning: passing 'NS_RETURNS_INNER_POINTER const char *' to parameter of type 'char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
cgo-gcc-export-header-prolog:60:33: note: passing argument to parameter 'str' here
darwin_ios.m:262:35: warning: 'userInterfaceStyle' is only available on iOS 12.0 or newer [-Wunguarded-availability-new]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/UIKit.framework/Headers/UITraitCollection.h:37:54: note: 'userInterfaceStyle' has been marked as being introduced in iOS 12.0 here, but the deployment target is iOS 7.0.0
darwin_ios.m:262:35: note: enclose 'userInterfaceStyle' in an @available check to silence this warning
darwin_ios.m:262:57: warning: 'UIUserInterfaceStyleDark' is only available on iOS 12.0 or newer [-Wunguarded-availability-new]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIInterface.h:32:28: note: 'UIUserInterfaceStyle' has been marked as being introduced in iOS 12.0 here, but the deployment target is iOS 7.0.0
darwin_ios.m:262:57: note: enclose 'UIUserInterfaceStyleDark' in an @available check to silence this warning
darwin_ios.m:316:33: warning: incompatible pointer types sending 'const CFStringRef _Nonnull' (aka 'const struct __CFString *const') to parameter of type 'id _Nonnull' [-Wincompatible-pointer-types]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:143:31: note: passing argument to parameter 'anObject' here
darwin_ios.m:321:94: warning: incompatible pointer types passing 'NSString *' to parameter of type 'CFStringRef _Nonnull' (aka 'const struct __CFString *') [-Wincompatible-pointer-types]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/CoreServices.framework/Headers/UTType.h:319:28: note: passing argument to parameter 'inTag' here
darwin_ios.m:323:37: warning: incompatible pointer types sending 'CFStringRef' (aka 'const struct __CFString *') to parameter of type 'id _Nonnull' [-Wincompatible-pointer-types]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:143:31: note: passing argument to parameter 'anObject' here
darwin_ios.m:331:99: warning: incompatible pointer types passing 'NSString *' to parameter of type 'CFStringRef _Nonnull' (aka 'const struct __CFString *') [-Wincompatible-pointer-types]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/CoreServices.framework/Headers/UTType.h:319:28: note: passing argument to parameter 'inTag' here
darwin_ios.m:333:33: warning: incompatible pointer types sending 'CFStringRef' (aka 'const struct __CFString *') to parameter of type 'id _Nonnull' [-Wincompatible-pointer-types]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:143:31: note: passing argument to parameter 'anObject' here
darwin_ios.m:349:29: warning: assigning to 'id<UIDocumentPickerDelegate> _Nullable' from incompatible type 'GoAppAppDelegate *'
darwin_ios.m:370:29: warning: assigning to 'id<UIDocumentPickerDelegate> _Nullable' from incompatible type 'GoAppAppDelegate *'
# fyne.io/fyne/v2/internal/driver/mobile
clipboard_ios.m:15:12: warning: returning 'NS_RETURNS_INNER_POINTER const char *' from a function with result type 'char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
# fyne.io/fyne/v2/internal/driver/mobile
folder_ios.m:12:112: warning: incompatible pointer to integer conversion sending 'void *' to parameter of type 'NSDirectoryEnumerationOptions' (aka 'enum NSDirectoryEnumerationOptions') [-Wint-conversion]
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/usr/include/MacTypes.h:94:19: note: expanded from macro 'nil'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/usr/include/sys/_types.h:52:23: note: expanded from macro '__DARWIN_NULL'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSFileManager.h:116:179: note: passing argument to parameter 'mask' here
folder_ios.m:29:12: warning: returning 'NS_RETURNS_INNER_POINTER const char *' from a function with result type 'char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
# fyne.io/fyne/v2/app
app_mobile_ios.m:15:12: warning: returning 'NS_RETURNS_INNER_POINTER const char *' from a function with result type 'char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
# github.com/sugarme/medpod-app
/usr/local/go/pkg/tool/darwin_amd64/link: running /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang failed: exit status 1
ld: framework not found AudioUnit
clang: error: linker command failed with exit code 1 (use -v to see invocation)
gen2brain commented 4 months ago

Ok, so remove it, check if frameworks are needed at all (try first without all of them), and check the correct name of the framework (maybe it is deprecated, renamed, etc.). I do not use macOS or iOS, so I don't know the details.

sugarme commented 4 months ago

@gen2brain,

If drop AudioUnit, seem to go forward, but got the following linking error:

/usr/local/go/pkg/tool/darwin_amd64/link: running /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang failed: exit status 1
Undefined symbols for architecture arm64:
  "_AVAudioSessionCategoryAmbient", referenced from:
      _ma_to_AVAudioSessionCategory in 000041.o
  "_AVAudioSessionCategoryMultiRoute", referenced from:
      _ma_to_AVAudioSessionCategory in 000041.o
  "_AVAudioSessionCategoryPlayAndRecord", referenced from:
      _ma_context_init__coreaudio in 000041.o
      _ma_to_AVAudioSessionCategory in 000041.o
  "_AVAudioSessionCategoryPlayback", referenced from:
      _ma_context_init__coreaudio in 000041.o
      _ma_to_AVAudioSessionCategory in 000041.o
  "_AVAudioSessionCategoryRecord", referenced from:
      _ma_context_init__coreaudio in 000041.o
      _ma_to_AVAudioSessionCategory in 000041.o
  "_AVAudioSessionCategorySoloAmbient", referenced from:
      _ma_to_AVAudioSessionCategory in 000041.o
  "_AVAudioSessionInterruptionNotification", referenced from:
      -[ma_ios_notification_handler init:] in 000041.o
      -[ma_ios_notification_handler remove_handler] in 000041.o
  "_AVAudioSessionInterruptionTypeKey", referenced from:
      -[ma_ios_notification_handler handle_interruption:] in 000041.o
  "_AVAudioSessionRouteChangeNotification", referenced from:
      -[ma_ios_notification_handler init:] in 000041.o
      -[ma_ios_notification_handler remove_handler] in 000041.o
  "_AVAudioSessionRouteChangeReasonKey", referenced from:
      -[ma_ios_notification_handler handle_route_change:] in 000041.o
  "_AudioComponentFindNext", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioComponentInstanceDispose", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioComponentInstanceNew", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioOutputUnitStart", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioOutputUnitStop", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitAddPropertyListener", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitGetProperty", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitGetPropertyInfo", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitInitialize", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitRender", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitSetProperty", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_OBJC_CLASS_$_AVAudioSession", referenced from:
      objc-class-ref in 000041.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I am on MacOS/amd64 box.

gen2brain commented 4 months ago

Ok, so a quick search shows that now AVFAudio framework is used, and your examples show that miniaudio does not use runtime linking on ios.

sugarme commented 4 months ago

@gen2brain,

What does it mean? Please explain and your suggestion? Ta

gen2brain commented 4 months ago

Add -framework AVFAudio, sorry, I thought that was clear.

sugarme commented 4 months ago

@gen2brain,

Now, I got

/usr/local/go/pkg/tool/darwin_amd64/link: running /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang failed: exit status 1
Undefined symbols for architecture arm64:
  "_AudioComponentFindNext", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioComponentInstanceDispose", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioComponentInstanceNew", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioOutputUnitStart", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioOutputUnitStop", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitAddPropertyListener", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitGetProperty", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitGetPropertyInfo", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitInitialize", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitRender", referenced from:
      _ma_context_init__coreaudio in 000041.o
  "_AudioUnitSetProperty", referenced from:
      _ma_context_init__coreaudio in 000041.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I feel we nearly there, just something missing. I am on MacOS/amd64 and try to cross-compile to iPhone which is arm64, not sure which is missing here.

sugarme commented 4 months ago

@gen2brain,

Finally, it compiled with the following added lines:


#cgo ios CFLAGS: -x objective-c
#cgo ios LDFLAGS: -framework CoreFoundation -framework AVFAudio -framework CoreAudio -framework AudioToolbox

I am happy to do PR with those lines but not sure if it could affect some other architectures. Please guide if you want to.

Thanks for your help.

gen2brain commented 4 months ago

Yes, please send a PR, it cannot affect others. While at it, please also change the README, i.e., you can change it to macOS/iOS (CoreAudio), thanks.