Azure / Communication

Azure Communication Services - SDKs and Release Notes
MIT License
320 stars 99 forks source link

[iOS] There is no choice for bottom speaker of iPhone, speaker name localization and unable to close speaker sound #108

Open devgokhan opened 3 years ago

devgokhan commented 3 years ago

Hi.

When we call getSpeakerList method, in the list only Build-in Speaker (top speaker (handset) of iPhone) is returns. However we need more sound and want to use bottom speaker but we can't.

We want also volume off the sound but I could not see any option for that. There is option mute available for call which only mutes microphone. But we need do that for speaker (mute/volume off). I thought maybe I can do that with deviceInfo.setSpeaker(nil) however parameter is not nullable so it is impossible to. How can I volume off?

We want to develop speaker chooser like Teams if it is possible we can give them different icons. There is 3 option we want to add in our app: 1- Build in speaker (top headset) 2- Bottom speaker (most loud speaker) 3- Volume off

mariusu-msft commented 3 years ago

@devgokhan - we will be removing the audio part of the DeviceManager soon and will revisit such need in the future.

As you pointed out, the stack will always default to earpiece. From there on, we expect developers to use native iOS APIs to switch the audio sink.

You can do this using something like this:

try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)

Please refer to Apple documentation on proper use: https://developer.apple.com/documentation/avfoundation/avaudiosession

We will keep this item open, until we have removed Device Manager, and updated documentation on how iOS audio routing should work.

tompi commented 3 years ago

@mariusu-msft I think this behaviour causes a lot of confusion and should be considered a bug. If you cant change speaker using ACS, I dont think ACS should SET speaker. It feels a bit strange that I now have to figure out WHEN to reset speakers, since I need to do it AFTER ACS has changed them... Also, if you HAVE TO set a speaker in ACS, the earpiece is not the logical choice for a video call...

devgokhan commented 3 years ago

Hi @mariusu-msft thank you for suggestion. Yes with this way we can switch handset to speaker and speaker to handset. But I am not sure is it better way or not. On the other hand I am still unable to volume off to output sound it seems it should be handled in audio source..

I write this code to handle this.Yeah currently I can say I can change speaker and handset.. I am not sure my code is correct and effects everything in app or not.. I think maybe it will be better wait your next documented solution or framework updates. Until this time I can use my code without volume off feature:

var speakerSources = [ValuePickerModel]()
let speakers = dm.getSpeakerList()
if let sps = speakers {
      for s in sps {
          speakerSources.append(ValuePickerModel(text: s.name, image: #imageLiteral(resourceName: "usa"), resultObject: s))
      }
     speakerSources.append(ValuePickerModel(text: "Speaker", image: #imageLiteral(resourceName: "usa"), resultObject: "speaker") )
     speakerSources.append(ValuePickerModel(text: "Sound Off", image: #imageLiteral(resourceName: "usa"), resultObject: "muteSound") )
}
PopupHelper(showOnViewController: self).showValuePicker(text: "Select Audio Source", items: speakerSources) { [weak self] (valuePickerModel) in
     if let deviceInfo = valuePickerModel.resultObject as? AudioDeviceInfo {
          dm.setSpeaker(speakerDevice: deviceInfo)
          self?.optionSpeakerButton.setActive(true)
          do {
              try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
              print("Meeting -> Volume speaker off sounds success")
           } catch {
                print("Meeting -> Unable to Volume speaker off sounds due to error: \(error.localizedDescription)")
            }
       } else if let stringInfo = valuePickerModel.resultObject as? String{
           if stringInfo == "muteSound" {
                // THERE IS NO SOLUTION YET FOR THIS
            } else if stringInfo == "speaker" {
                 do {
                      try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
                       print("Meeting -> Volume speaker on")
                  } catch {
                        print("Meeting -> Unable to Volume speaker on due to error: \(error.localizedDescription)")
                  }
             }
      }
}
tompi commented 3 years ago

For anybody else struggling with this, if you need loudspeaker output by default, it seems to work okay to override audio output like marius suggested on call state-change, when call has gone into "connected" state. ACSCallDelegate -> OnCallStateChanged -> call.state == connected