I have a button that should go from EARPIECE to SPEAKER to BLUETOOTH and so on.
This is my code:
fun setSpeakerValue(value: SIPManager.AUDIO) {
speaker = value
when (value) {
SIPManager.AUDIO.EAR_PIECE -> {
Log.i("Speaker", "Speaker1 EARPIECE")
binding.callItemIconSpeaker.setImageResource(R.drawable.speaker_off)
if (SIPManager.isBluetoothConnected()) {
audioManager?.isBluetoothScoOn = false
audioManager?.stopBluetoothSco()
}
audioManager?.mode = AudioManager.MODE_NORMAL
audioManager?.isSpeakerphoneOn = false
}
SIPManager.AUDIO.SPEAKER -> {
Log.i("Speaker", "Speaker1 SPEAKER")
binding.callItemIconSpeaker.setImageResource(R.drawable.speaker_on)
if (SIPManager.isBluetoothConnected()) {
audioManager?.isBluetoothScoOn = false
audioManager?.stopBluetoothSco()
}
audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION
audioManager?.isSpeakerphoneOn = true
}
SIPManager.AUDIO.BLUETOOTH -> {
Log.i("Speaker", "Speaker1 BLUETOOTH")
binding.callItemIconSpeaker.setImageResource(android.R.drawable.stat_sys_data_bluetooth)
audioManager?.mode = AudioManager.MODE_NORMAL
audioManager?.isSpeakerphoneOn = false
audioManager?.startBluetoothSco()
audioManager?.isBluetoothScoOn = true
}
}
}
But wheneven I ste to earpiece, I stopBluetoothSCO, I set isSpeakerOn to false, but after that, I start hearing in the blueooth instead of the earpiece of the phone. What am I doing wrong?
Got it to work using the answer from here:
How to switch audio output from Phone, Phone Speaker, earphones or Bluetooth device
//For BT
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
mAudioManager.startBluetoothSco();
mAudioManager.setBluetoothScoOn(true);
} else if(true) {
//For phone ear piece
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
mAudioManager.stopBluetoothSco();
mAudioManager.setBluetoothScoOn(false);
mAudioManager.setSpeakerphoneOn(false);
} else {
//For phone speaker(loudspeaker)
mAudioManager.setMode(AudioManager.MODE_NORMAL);
mAudioManager.stopBluetoothSco();
mAudioManager.setBluetoothScoOn(false);
mAudioManager.setSpeakerphoneOn(true);
}
Related
Every time I submit an achievement to Game Center on macOS, using Mac Catalyst, my game crashes with this:
-[GKAchievementInternal showBanner]: unrecognized selector sent to instance 0x600002616ca0
No call stack. I set a break point for all the Obj-C exceptions but it's just stopped in the AppDelegate.
Everything is fine on iOS and iPadOS, and the rest of the Game Center behaviour on macOS seems to be fine.
For reference, this is how I submit the achievements:
private func submitAchievements(_ aList: [Achievement]) {
if !isGameCenterEnabled {
return
}
var achievements : [GKAchievement] = []
for kvp in AchievementFromId {
if aList.contains(kvp.1) {
let achievement = GKAchievement(identifier: kvp.0)
achievement.showsCompletionBanner = true
achievement.percentComplete = 100.0
achievements.append(achievement)
}
}
if achievements.count > 0 {
GKAchievement.report(achievements, withCompletionHandler: { (error: Error?) -> Void in
if let err = error {
NSLog("submitAchievements: \(err.localizedDescription)")
}
})
}
}
That function uses these data structures:
enum Achievement : Int {
case
clearTutorial = 0x00000001,
clearLevel1 = 0x00000002,
clearLevel2 = 0x00000004,
}
let AchievementFromId : [String : Achievement] = [
"Tutorial": .clearTutorial,
"Level1": .clearLevel1,
"Level2": .clearLevel2,
]
Edit:
I filed a feedback with the Feedback Assistant. In the meantime, the only workaround I found is disabling the completion banners on macOS:
#if targetEnvironment(macCatalyst)
achievement.showsCompletionBanner = false
#else
achievement.showsCompletionBanner = true
#endif
Also, to reset the achievements and test this, I use this function:
GKAchievement.resetAchievements() { error in
if let error = error {
NSLog("resetAchievements: \(error.localizedDescription)")
} else if let fn = onCompletion {
syncAchievements() // function that resubmits all the achievements again
}
}
This was a bug in macOS Catalina. Apple has resolved this in macOS 11 Big Sur (Feedback reference: FB7847659)
They don't have plans to fix this on Catalina.
For Catalina, just avoid showing banners with achievement.showsCompletionBanner = false. This looks a bit ugly, but I did this:
#if targetEnvironment(macCatalyst)
let os = ProcessInfo().operatingSystemVersion
achievement.showsCompletionBanner = os.majorVersion >= 11
#else
achievement.showsCompletionBanner = true
#endif
Note that I use ProcessInfo() because for some reason if #available(macOS 11.0, *) returns true in Catalina as well.
I'm using AVAssetResourceLoader to load data and AVPlayerViewController to play.
It works properly under iOS10, 11 but not work any more under iOS12.
When playing, the process bar is moving forward, but the video only plays 1 sec, and stuck till end.
Here's my AVAssetResourceLoader code:
class MediaResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
func resourceLoader(
_ resourceLoader: AVAssetResourceLoader,
shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest
) -> Bool {
loadingRequest.contentInformationRequest?.contentType = kUTTypeMPEG4 as String
loadingRequest.contentInformationRequest?.contentLength = Int64(self.data.count)
loadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
guard let request = loadingRequest.dataRequest else { return false }
if request.requestsAllDataToEndOfResource {
request.respond(with: data)
} else if Int(request.requestedOffset) <= request.requestedLength {
let subData = self.data.subdata(in: Int(request.requestedOffset)..<request.requestedLength)
request.respond(with: subData)
}
loadingRequest.finishLoading()
return true
}
}
Trying to make a flash light application, I am not getting it working. This is my code:
public void setFlash(Controllable player) {
FlashControl flashControl =
(FlashControl) getControl(player, "javax.microedition.amms.control.camera.FlashControl");
if (flashControl != null) {
int[] supportedFlash = flashControl.getSupportedModes();
if (supportedFlash != null && supportedFlash.length > 0) {
for (int i = 0; i < supportedFlash.length; i++) {
if (supportedFlash[i] == DESIRED_FLASH) {
try {
flashControl.setMode(DESIRED_FLASH);
} catch (IllegalArgumentException iae) {
// continue
}
break;
}
}
}
}
}
According to JSR 234 documentation FlashControl has six public constants:
AUTO: The camera will autoflash according to the lighting condition
AUTO_WITH_REDEYEREDUCE: The camera will autoflash according to the lighting conditions and if it flashes it will use red-eye reduction
FILLIN: Reduced flash
FORCE: Camera flash is on
FORCE_WITH_REDEYEREDUCE: Camera flash is on and red-eye reduction is in use
OFF: Camera flash is off
You should use FORCE or FORCE_WITH_REDEYEREDUCE
I am using ionic cordova media plugin to record audio from the user's phone. Once recorded i get the file to play and everything is fine. I just want to get the duration of the file and when i play the recorded file i want to show the minutes::seconds of the file being played. How do i do that?
record_audio(){
this.file.startRecord();
this.recording = true;
/*
let record_opt: CaptureAudioOptions = { limit: 1 };
this.mediacapture.captureAudio(record_opt).then(
(data: MediaFile[]) => alert('audio recorded'),
(err: CaptureError)=> alert('cannot record')
);
*/
}
cancel_record(){
this.file.release();
this.show_record_div = false;
this.recordedfile_available = false;
}
stop_recording(){
this.file.stopRecord();
this.recording = false;
this.recordedfile_available = true;
//this.filelength = this.file.getDuration();
}
play_recorded(){
this.file.play();
}
stop_playing(){
this.file.stop();
}
try this.
let duration = this.file.getDuration();
console.log(duration);
// get current playback position
file.getCurrentPosition().then((position) => {
console.log(position);
});
I am using the sample from Microsoft. When an advertisement is received I am calling
BluetoothLEDevice device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
and then
device.GattServices()
but that always returns an empty list. Why is this happening? I have found no answer whatsoever.
If you want this to work by using advertisement watcher, you need to target the windows 10 creators update(10.0;Build 15063) and use the latest SDK, otherwise you will have to pair the device first.
To get the GattServices, first check if the device is not null.
Then use:
var serviceResult = await bluetoothLeDevice.GetGattServicesAsync();
if (serviceResult.Status == GattCommunicationStatus.Success)
{
//Do something with servivicResult list
}
But there is a catch; It can be that serviceResult.Status returns success, but not all or no services have been found yet.
My solution is to put it in a loop with a short delay and try it a few times until serviceResult count stays the same.
I wanted to put more explanation in my comment, but something went wrong and cannot edit my comment so I will add it as an answer.
I had exactly the same problem. for some reason you have to initialize your BLEdevice as null.
private BluetoothLEDevice device = null;
Also to prevent that you advertisementWatcher is setting your device over and over, use an if statement to set it only when the divice is null,
if (device == null)
{
device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
}
or if you want to set multiple devices than add them to a collection and make sure each device is only added once.
This is my working code :
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher,
BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
BluetoothLEAdvertisementType advertisementType = eventArgs.AdvertisementType;
short rssi = eventArgs.RawSignalStrengthInDBm;
string localName = eventArgs.Advertisement.LocalName;
string manufacturerDataString = "";
var manufacturerSections = eventArgs.Advertisement.ManufacturerData;
if (manufacturerSections.Count > 0)
{
// Only print the first one of the list
var manufacturerData = manufacturerSections[0];
var data = new byte[manufacturerData.Data.Length];
using (var reader = DataReader.FromBuffer(manufacturerData.Data))
{
reader.ReadBytes(data);
}
manufacturerDataString = string.Format("0x{0}: {1}",
manufacturerData.CompanyId.ToString("X"),
BitConverter.ToString(data));
}
string res = string.Format("type={0}, rssi={1}, name={2}, manufacturerData=[{3}]",
advertisementType.ToString(),
rssi.ToString(),
localName,
manufacturerDataString);
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
textBoxWatcher.Text = res;
});
if (device == null)
{
device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
if (device != null)
{
var deviceInfo = device.DeviceInformation;
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
if (device.Name != string.Empty)
{
//ResultCollection is a observable observable collection of blueutooth devices
// to bind to a listvieuw,it is not needed!
ResultCollection.Add(new BleDevice(device));
if (deviceInfo.Name == "HMSoft")
{
if (ResultCollection[0] is BleDevice bleDevice)
{
BleDeviceId = bleDevice.Id;
SelectedBleDeviceName = bleDevice.Name;
}
Connect();
}
}
});
}
}