Twilio client voice call speaker ON/OFF issue - ios

I am using Twilio client voice call service for calling.
Here I am facing issue in spearke ON/OFF feature.I am able to Mute/Unmute call but not able to turn On/OFF speaker. I have a same instance for both functionality. I have also checked their demo project basic phone in that this speaker ON/OFF is working and I am doing same thing in my project bur not able to do the same.
Here is my code:
if(isSpeaker == NO)
{
isSpeaker=YES;
[self.phone setSpeakerEnabled:YES];
}
else{
isSpeaker=NO;
[self.phone setSpeakerEnabled:NO];
}
self.phone is the sharedInstance of BasicPhone (their call manager class) and I am testing application in > iOS 9 both demo and my project.

I've used this code on iOS to successfully enable/disable speakerphone. It doesn't use the Twilio device, and is somewhat specific to React Native, but the core of each function should work:
RCT_EXPORT_METHOD(setSpeakerPhoneOn) {
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error;
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
}
RCT_EXPORT_METHOD(setSpeakerPhoneOff) {
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error;
[session overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&error];
}

Swift 5, use below code snippet
// Change the audio route after connecting to a Room.
func moveToMic() {
audioDevice.block = {
DefaultAudioDevice.DefaultAVAudioSessionConfigurationBlock()
do {
try AVAudioSession.sharedInstance().setMode(.voiceChat)
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
} catch {
print(error)
}
}
audioDevice.block();
}
func moveToSpeaker() {
audioDevice.block = {
DefaultAudioDevice.DefaultAVAudioSessionConfigurationBlock()
do {
try AVAudioSession.sharedInstance().setMode(.videoChat)
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
} catch {
print(error)
}
}
audioDevice.block();
}

Related

Routing audio output between multiple bluetooth devices with iOS using AVAudioSession

Got a video conference app, implementing device selection feature of switching between Earpiece, Speaker, and connected Bluetooth devices. All seems to function appropriately apart from switching between bluetooth devices themselves.
For some reason, only the last connected device gets the audio routed to it, and you can't switch back to the other ones even if they're available in availableInputs of AVAudioSession SharedInstance, using setPreferredInput with OverridePortNone
I tried searching for resolutions but found the same unanswered issue from 5 years ago, I tried doing the same as changing setActive calls but was also unsuccessful.
Following is the test code, which is taken from here:
AVAudioSession *_audioSession = [AVAudioSession sharedInstance];
AVAudioSessionCategoryOptions _incallAudioCategoryOptionsAll = AVAudioSessionCategoryOptionMixWithOthers|AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionAllowAirPlay;
[_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:_incallAudioCategoryOptionsAll
error:nil];
[_audioSession setMode:AVAudioSessionModeVoiceChat error: nil];
RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject) {
BOOL success;
NSError *error = nil;
NSLog(#"[setAudioDevice] - Attempting to set audiodevice as: %#", device);
if ([device isEqualToString:kDeviceTypeSpeaker]) {
success = [_audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
} else {
AVAudioSessionPortDescription *port = nil;
for (AVAudioSessionPortDescription *portDesc in _audioSession.availableInputs) {
if ([portDesc.UID isEqualToString:device]) {
port = portDesc;
break;
}
}
if (port != nil) {
[_audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
success = [_audioSession setPreferredInput:port error:&error];
if(error != nil)
{
NSLog(#"setAudioDevice %# %#", error.localizedDescription, error);
}
} else {
success = NO;
error = RCTErrorWithMessage(#"Could not find audio device");
}
}
if (success) {
resolve(#"setAudioDevice success!");
NSLog(#"resolved success");
} else {
reject(#"setAudioDevice", error != nil ? error.localizedDescription : #"", error);
NSLog(#"sent reject");
}
}
So how can I make it that we're able to successfully change from one bluetooth device to other?

How can stream Audio when iPhone is locked?

I'm working on AppRTC for Audio call, It's working fine when app is open. Audio call is not working when device is locked, If wI un-lock device while call and open app, It's start working normally but while it's locked it's not working. (Audio is not passing or playing).
I already added "App plays audio or streams audio/video using AirPlay" in "Required background modes" of plist.
Audio session is also configured. Please check code below.
- (void)configureAVAudioSession:(BOOL)isSpeakerOn
{
// Get your app's audioSession singleton object
AVAudioSession *session = [AVAudioSession sharedInstance];
// Error handling
BOOL success;
NSError *error;
// set the audioSession category.
// Needs to be Record or PlayAndRecord to use audioRouteOverride:
success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
error:&error];
if (!success) {
NSLog(#"AVAudioSession error setting category:%#",error);
}
// Set the audioSession override
success = [session overrideOutputAudioPort:isSpeakerOn?AVAudioSessionPortOverrideSpeaker:AVAudioSessionPortOverrideNone
error:&error];
if (!success) {
NSLog(#"AVAudioSession error overrideOutputAudioPort:%#",error);
}
// Activate the audio session
success = [session setActive:YES error:&error];
if (!success) {
NSLog(#"AVAudioSession error activating: %#",error);
}
else {
NSLog(#"AudioSession active");
}
}
Please let me know if anything is missing or i'd implemented wrongly.
Regards,

How to let my app audio to nicely interrupt iPhone audio while speaking

My iOS 7 app vocalizes texts when necessary.
What I'd like to do is enable the user to listen to his music or podcasts (or any other app using audio) while mine is running.
The expected behavior is that others audio either mixe or duck when my app speaks, then the others audio resume his volume at the initial level right after.
I have tried many ways to achieve this goal, but nothing is good enough, as I list the issues I face, after the code.
My current implementation is based on creating a session prior to play or text-to-speech as follows:
+ (void)setAudioActive {
[[self class] setSessionActiveWithMixing:YES];
}
After the play/speech, I set i to idled as follows:
+ (void)setAudioIdle {
[[self class] setSessionActiveWithMixing:NO];
}
The core function which handle the session setup accordingly to the active parameter, as follows:
+ (void)setSessionActiveWithMixing:(BOOL)active
{
NSError *error = NULL;
BOOL success;
AVAudioSession *session = [AVAudioSession sharedInstance];
static NSInteger counter = 0;
success = [session setActive:NO error:&error];
if (error) {
DDLogError(#"startAudioMixAndBackground: session setActive:NO, %#", error.description);
}
else {
counter--; if (counter<0) counter = 0;
}
if (active) {
AVAudioSessionCategoryOptions options = AVAudioSessionCategoryOptionAllowBluetooth
//|AVAudioSessionCategoryOptionDefaultToSpeaker
|AVAudioSessionCategoryOptionDuckOthers
;
success = [session setCategory://AVAudioSessionCategoryPlayback
AVAudioSessionCategoryPlayAndRecord
withOptions: options
error: &error];
if (error) {
// Do some error handling
DDLogError(#"startAudioMixAndBackground: setCategory:AVAudioSessionCategoryPlayback, %#", error.description);
}
else {
//activate the audio session
success = [session setActive:YES error:&error];
if (error) {
DDLogError(#"startAudioMixAndBackground: session setActive:YES, %#", error.description);
}
else {
counter++;
}
}
}
DDLogInfo(#"Audio session counter is: %ld",counter);
}
My current issues are:
1) When my app start to speak, I hear some king of glitch in the sound, which makes it not nice;
2) When I connect the route to bluetooth, the underlying audio (say the Podcast or ipod music) goes very low and sounds noisy, which make my solution merely unusable, my users will reject this level au poor quality.
3) When others bluetooth connected devices tried to emit sounds (say a GPS in a car or instance), my App does not receive any interrupts (or I handle it wrongly), see my code as follows:
- (void)startAudioMixAndBackground {
// initialize our AudioSession -
// this function has to be called once before calling any other AudioSession functions
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(audioSessionDidChangeInterruptionType:)
name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
// set our default audio session state
[[self class] setAudioIdle];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
if ([self canBecomeFirstResponder]) {
[self becomeFirstResponder];
}
#synchronized(self) {
self.okToPlaySound = YES;
}
//MPVolumeSettingsAlertShow();
}
// want remote control events (via Control Center, headphones, bluetooth, AirPlay, etc.)
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
if (event.type == UIEventTypeRemoteControl)
{
switch(event.subtype)
{
case UIEventSubtypeRemoteControlPause:
case UIEventSubtypeRemoteControlStop:
[[self class] setAudioIdle];
break;
case UIEventSubtypeRemoteControlPlay:
[[self class] setAudioActive];
break;
default:
break;
}
}
}
#pragma mark - Audio Support
- (void)audioSessionDidChangeInterruptionType:(NSNotification *)notification
{
AVAudioSessionInterruptionType interruptionType = [[[notification userInfo]
objectForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
if (AVAudioSessionInterruptionTypeBegan == interruptionType)
{
DDLogVerbose(#"Session interrupted: --- Begin Interruption ---");
}
else if (AVAudioSessionInterruptionTypeEnded == interruptionType)
{
DDLogVerbose(#"Session interrupted: --- End Interruption ---");
}
}
Your issue is most likely due to the category you are setting: AVAudioSessionCategoryPlayAndRecord. The PlayAndRecord category does not allow your app to mix/duck audio with other apps. You should reference the docs on Audio Session Categories again here: https://developer.apple.com/library/ios/documentation/avfoundation/reference/AVAudioSession_ClassReference/Reference/Reference.html. It seems like AVAudioSessionCategoryAmbient is probably more what your looking for.

How Do I Route Audio to Speaker without using AudioSessionSetProperty?

As AudioSessionSetProperty may become deprecated, I'm trying to find an code example of how to route audio to the speaker using other means.
Previously I did the following:
-(void)setSpeakerEnabled
{
debugLog(#"%s",__FUNCTION__);
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (
kAudioSessionProperty_OverrideAudioRoute,
sizeof (audioRouteOverride),
&audioRouteOverride
);
}
Trying to get same result but without call to AudioSessionSetProperty.
On each release of iOS, more of the audioSession properties are migrated to AVFoundation, so you should use those in preference whenever available.
Since iOS 6 kAudioSessionProperty_OverrideAudioRoute is represented in AVAudioSession by the method
- (BOOL)overrideOutputAudioPort:error:
Available values are AVAudioSessionPortOverrideNone and AVAudioSessionPortOverrideSpeaker
Here is an example audio session configured entirely via AVFoundation:
- (void)configureAVAudioSession
{
// Get your app's audioSession singleton object
AVAudioSession *session = [AVAudioSession sharedInstance];
// Error handling
BOOL success;
NSError *error;
// set the audioSession category.
// Needs to be Record or PlayAndRecord to use audioRouteOverride:
success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
error:&error];
if (!success) {
NSLog(#"AVAudioSession error setting category:%#",error);
}
// Set the audioSession override
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:&error];
if (!success) {
NSLog(#"AVAudioSession error overrideOutputAudioPort:%#",error);
}
// Activate the audio session
success = [session setActive:YES error:&error];
if (!success) {
NSLog(#"AVAudioSession error activating: %#",error);
}
else {
NSLog(#"AudioSession active");
}
}
UPDATE
Since iOS 7.0, the Audio Session Services C API is now fully deprecated in favour of AVAudioSession.
UPDATE 2
- (BOOL)overrideOutputAudioPort:error:
is a method, not a property, and it sets an underlying write-only UInt32 value. You can't get the current value, and you should treat the method as setting a temporary state. If the audio route changes or is interrupted, the property resets to its default (AVAudioSessionPortOverrideNone). You can get interruption notifications via AVAudioSessionDelegate.
NSError *error;
[[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:&error];
if(error)
{
NSLog(#"Error: AudioSession cannot use speakers");
}
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSession.Category.playAndRecord, mode: .spokenAudio, options: .defaultToSpeaker)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
} catch {
print("error.")
}
// paste this code in your viewLoad region
Foundry’s solution together with this blog by Mario Diana has also allowed me to upgrade audio session set up code deprecated in iOS 7. My old code was based on
AudioBufferPlayer by Matthijs Hollemans.
Remember to add the AVFoundation.framework.

How to play audio with OutputAudioQueue in silent mode? [duplicate]

I want to play a sound even in silent mode in iPhone.
Can it be done by using AVAudioPlayer (Without using AVAudioSession)
(For ios 3.0+)
Thanks in advance.
Actually, you can do this. It is controlled via the Audio Session and has nothing to do with AVAudioPlayer itself. Why don't you want to use AudioSession? They play nice together...
In your app, you should initialize the Audio Session, and then you can also tell indicate what kind of audio you intend to play. If you're a music player, then it sort of makes sense that the user would want to hear the audio even with the ring/silent switch enabled.
AudioSessionInitialize (NULL, NULL, NULL, NULL);
AudioSessionSetActive(true);
// Allow playback even if Ring/Silent switch is on mute
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory,
sizeof(sessionCategory),&sessionCategory);
I have an app that I do this very thing, and use AVAudioPlayer to play audio, and with the ring/silent switch enabled, I can hear the audio.
UPDATE (11/6/2013)
In the app I mentioned above, where I used the code above successfully, I have (for some time) been using the following code instead to achieve the same result:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
BOOL result = NO;
if ([audioSession respondsToSelector:#selector(setActive:withOptions:error:)]) {
result = [audioSession setActive:YES withOptions:0 error:&error]; // iOS6+
} else {
[audioSession setActive:YES withFlags:0 error:&error]; // iOS5 and below
}
if (!result && error) {
// deal with the error
}
error = nil;
result = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
if (!result && error) {
// deal with the error
}
I thought I'd post this as an alternative, in light of the most recent comment to this answer. :-)
MarkGranoff's solution is correct. However, if you prefer to do it in Obj-c instead of C, the following works as well:
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
The above answers are correct. Following is the Swift version.
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
//print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
//print("AVAudioSession is Active")
} catch _ as NSError {
//print(error.localizedDescription)
}
} catch _ as NSError {
//print(error.localizedDescription)
}
Swift 4 simple version:
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
This will simply do the trick (using AVAudioSession)
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)

Resources