Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add toggle to change Audio Session behaviour #10

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
## 0.3.0+1
## 0.4.0

* Adds support for older Android and iOS versions
* Adds an option to toggle the audio session behaviour on iOS
* Updates package dependencies

* ## 0.3.0+1

* Update readme.

Expand Down
7 changes: 4 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ group 'com.codevalop.raw_sound'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.8.21'
repositories {
google()
jcenter()
Expand All @@ -25,13 +25,14 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 30
namespace 'com.codevalop.raw_sound'
compileSdkVersion 33

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
minSdkVersion 24
minSdkVersion 23
}
lintOptions {
disable 'InvalidPackage'
Expand Down
2 changes: 1 addition & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ android {

defaultConfig {
applicationId "com.codevalop.raw_sound_example"
minSdkVersion 24
minSdkVersion 23
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
Expand Down
2 changes: 1 addition & 1 deletion example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="raw_sound_example"
android:icon="@mipmap/ic_launcher">
<activity
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# platform :ios, '11.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1230;
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1230"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
2 changes: 2 additions & 0 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: Demonstrates how to use the raw_sound plugin.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev

environment:
sdk: '>=2.12.0-133.2.beta <3.0.0'
sdk: '>=2.18.0 <3.0.0'

dependencies:
flutter:
Expand Down
58 changes: 10 additions & 48 deletions ios/Classes/RawSoundPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ public enum PCMType: Int {
}

class RawSoundPlayer {
private let logger = Logger(
subsystem: "com.codevalop.raw_sound", category: "RawSoundPlayer")

private let audioEngine = AVAudioEngine()
private let playerNode = AVAudioPlayerNode()
Expand Down Expand Up @@ -43,17 +41,18 @@ class RawSoundPlayer {

private let pcmType: PCMType

init?(bufferSize: Int, sampleRate: Int, nChannels: Int, pcmType: PCMType) {
init?(bufferSize: Int, sampleRate: Int, nChannels: Int, pcmType: PCMType, configureAudioSession: Bool) {
precondition(
nChannels == 1 || nChannels == 2,
"Only support one or two channels")

let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback, mode: .default)
} catch {
logger.error("\(error.localizedDescription)")
return nil
if(configureAudioSession) {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback, mode: .default)
} catch {
return nil
}
}

// init?(commonFormat: AVAudioCommonFormat, sampleRate: Double, channels: AVAudioChannelCount, interleaved: Bool)
Expand Down Expand Up @@ -82,7 +81,6 @@ class RawSoundPlayer {
playerNode, to: audioEngine.outputNode, format: outputFormat)
audioEngine.prepare()
buffers.reserveCapacity(buffersCacheSize)
logger.info("initialized")
}

func release() -> Bool {
Expand All @@ -104,27 +102,21 @@ class RawSoundPlayer {

func play() -> Bool {
if !audioEngine.isRunning {
logger.error("audio engine is not running")

do {
logger.debug("--> starting audio engine")
try audioEngine.start()
logger.debug("<-- starting audio engine")
} catch {
logger.error("\(error.localizedDescription)")
return false
}
}
logger.debug("--> starting player")

playerNode.play()
logger.debug("<-- starting player")
isPaused = false

queUseBuffer.async {
self.logger.debug("--> queUseBuffer")
self.queUseBufferIdled.wait()
defer {
self.queUseBufferIdled.signal()
self.logger.debug("<-- queUseBuffer")
}

let n = self.buffersCacheSize - self.getBuffersCount()
Expand All @@ -145,9 +137,7 @@ class RawSoundPlayer {
buffer,
completionCallbackType: .dataConsumed,
completionHandler: { _ in
// self.logger.debug("--> completionHandler")
self.semBufferUsed.signal()
// self.logger.debug("<-- completionHandler")
}
)
}
Expand All @@ -163,21 +153,17 @@ class RawSoundPlayer {
resetSemBufferAdded()
}
guard audioEngine.isRunning else {
logger.error("audio engine is not running")
return true
}
if playerNode.isPlaying {
logger.debug("--> stopping player")
playerNode.stop()
logger.debug("<-- stopping player")
isPaused = false
}
return true
}

func pause() -> Bool {
guard audioEngine.isRunning else {
logger.error("audio engine is not running")
return false
}
if playerNode.isPlaying {
Expand All @@ -189,7 +175,6 @@ class RawSoundPlayer {

func resume() -> Bool {
guard audioEngine.isRunning else {
logger.error("audio engine is not running")
return false
}
if !playerNode.isPlaying {
Expand All @@ -201,22 +186,18 @@ class RawSoundPlayer {

func feed(data: [UInt8], onDone: @escaping (_ r: Bool) -> Void) {
guard audioEngine.isRunning else {
logger.error("audio engine is not running")
onDone(false)
return
}
guard playerNode.isPlaying else {
logger.error("player is not playing")
onDone(true)
return
}

queAddBuffer.async {
// self.logger.debug("--> queAddBuffer")
self.queAddBufferIdled.wait()
defer {
self.queAddBufferIdled.signal()
// self.logger.debug("<-- queAddBuffer")
}
let buffer = self.dataToBuffer(data)
self.addBuffer(buffer)
Expand All @@ -235,7 +216,6 @@ class RawSoundPlayer {

func setVolume(_ volume: Float) -> Bool {
guard audioEngine.isRunning else {
logger.error("audio engine is not running")
return false
}
playerNode.volume = volume
Expand Down Expand Up @@ -291,9 +271,6 @@ class RawSoundPlayer {
}

// let iData = audioBuffer.int16ChannelData![0]
// self.logger.debug(
// "iData: \(iData[0]) \(iData[1]) \(iData[2]) \(iData[3]) \(iData[4]) \(iData[5]) \(iData[6]) ..."
// )

let audioConverter = AVAudioConverter(from: inputFormat, to: outputFormat)!
let ratio = Double(outputFormat.sampleRate) / Double(inputFormat.sampleRate)
Expand All @@ -309,21 +286,6 @@ class RawSoundPlayer {
return audioBuffer
})

if r != .haveData {
logger.debug("unexpected convert result: \(r.rawValue)")
}

if let err = error {
logger.error("\(err.localizedDescription)")
}

// logger.debug("convertedAudioBuffer.frameLength: \(convertedAudioBuffer.frameLength)")

// let fData = convertedAudioBuffer.floatChannelData![0]
// self.logger.debug(
// "fData: \(fData[0]) \(fData[1]) \(fData[2]) \(fData[3]) \(fData[4]) \(fData[5]) \(fData[6]) ..."
// )

return convertedAudioBuffer
}

Expand Down
19 changes: 7 additions & 12 deletions ios/Classes/RawSoundPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ public class RawSoundPlugin: NSObject, FlutterPlugin {
registrar.addMethodCallDelegate(instance, channel: channel)
}

private let logger = Logger(
subsystem: "com.codevalop.raw_sound", category: "RawSoundPlugin")

private let channel: FlutterMethodChannel
private var players = [RawSoundPlayer]()

init(channel: FlutterMethodChannel) {
self.channel = channel
super.init()
logger.info("initialized")
}

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
Expand All @@ -33,13 +29,10 @@ public class RawSoundPlugin: NSObject, FlutterPlugin {
if playerNo < 0 || playerNo > players.count - 1 {
result(
FlutterError(code: "Invalid Args", message: "Invalid playerNo: $playerNo", details: nil))
logger.error("Invalid playerNo: \(playerNo)")
return
}
}

// logger.debug("call.method: \(call.method)")

switch call.method {
case "getPlatformVersion":
result("iOS \(UIDevice.current.systemVersion)")
Expand All @@ -48,9 +41,12 @@ public class RawSoundPlugin: NSObject, FlutterPlugin {
let sampleRate = args["sampleRate"] as! Int
let nChannels = args["nChannels"] as! Int
let pcmType: PCMType = PCMType(rawValue: args["pcmType"] as! Int)!
let configureAudioSession = args["configureAudioSession"] as! Bool
initialize(
bufferSize: bufferSize, sampleRate: sampleRate,
nChannels: nChannels, pcmType: pcmType, result: result)
nChannels: nChannels, pcmType: pcmType, configureAudioSession: configureAudioSession,
result: result
)
case "release":
release(playerNo: playerNo, result: result)
case "play":
Expand All @@ -64,8 +60,6 @@ public class RawSoundPlugin: NSObject, FlutterPlugin {
case "feed":
let _data = args["data"] as! FlutterStandardTypedData
let data: [UInt8] = [UInt8](_data.data)
// logger.debug("data: \(data[0]) \(data[1]) \(data[2]) \(data[3]) ...")
// logger.debug("data.count: \(data.count)")
feed(playerNo: playerNo, data: data, result: result)
case "setVolume":
let volume = args["volume"] as! Float
Expand All @@ -91,13 +85,14 @@ public class RawSoundPlugin: NSObject, FlutterPlugin {
}

private func initialize(
bufferSize: Int, sampleRate: Int, nChannels: Int, pcmType: PCMType,
bufferSize: Int, sampleRate: Int, nChannels: Int, pcmType: PCMType, configureAudioSession: Bool,
result: @escaping FlutterResult
) {
guard
let player = RawSoundPlayer(
bufferSize: bufferSize, sampleRate: sampleRate,
nChannels: nChannels, pcmType: pcmType)
nChannels: nChannels, pcmType: pcmType,
configureAudioSession: configureAudioSession)
else {
sendResultError(
"Error", message: "Failed to initalize", details: nil, result: result)
Expand Down
2 changes: 1 addition & 1 deletion ios/raw_sound.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ A new flutter plugin project.
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'Flutter'
s.platform = :ios, '14.0'
s.platform = :ios, '12.0'

# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
Expand Down
3 changes: 3 additions & 0 deletions lib/raw_sound_platform.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:typed_data';

import 'package:flutter/services.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

Expand Down Expand Up @@ -28,12 +29,14 @@ class RawSoundPlayerPlatform extends PlatformInterface {
int nChannels = 1,
int sampleRate = 16000,
int pcmType = 0,
bool configureAudioSession = true,
}) async {
final playerNo = await _channel.invokeMethod<int>('initialize', {
'bufferSize': bufferSize,
'nChannels': nChannels,
'sampleRate': sampleRate,
'pcmType': pcmType,
'configureAudioSession': configureAudioSession,
});
_players[player] = playerNo!;
}
Expand Down
Loading