Check if audio playing with Python on Windows 10 - python-3.x

I'm working with Python 3.7 on Windows 10.
I would like to detect if there is any audio playing on my computer or not.
I was looking into win32api.GetVolumeinformation but I'm unable to get what I want.
When you control your audio you can see if there is a program playing and I want to achieve that.

Try this api using winrt:
The enum options are listed here, but you can use mediaIs("PAUSED"), mediaIs("PLAYING") ect...
import asyncio, winrt.windows.media.control as wmc
async def getMediaSession():
sessions = await wmc.GlobalSystemMediaTransportControlsSessionManager.request_async()
session = sessions.get_current_session()
return session
def mediaIs(state):
session = asyncio.run(getMediaSession())
if session == None:
return False
return int(wmc.GlobalSystemMediaTransportControlsSessionPlaybackStatus[state]) == session.get_playback_info().playback_status #get media state enum and compare to current main media session state
There are heaps more useful winrt APIs to control media on windows too here.

Related

functions.contacts.SearchRequest() only returns a small amount of results while mobile and desktop featured apps return much more

Using this minimally contrived example I am attempting to globally search within telegram using the telethon library:
# file.py:
import asyncio
from telethon.sync import TelegramClient
from telethon import functions
from sys import argv
async def main():
query = argv[1]
async with TelegramClient("debug.session", <api_id>, "<api_hash>") as client:
result = await client(functions.contacts.SearchRequest(
q=query,
limit=100
))
print(result.stringify())
if __name__ == '__main__':
asyncio.run(main())
# Usage: python3 <file.py> <query>
The results returned from functions.contacts.SearchRequest are very minuscule in comparison to the same query on the same account making the telethon-query within a telegram featured application (desktop, mobile). I tested on each platform's application (IOS, Linux, Android, Windows, MAC) the search results are always larger in-app versus searching with functions.contacts.SearchRequest using python3. I repeated/tested this on other accounts as well and it seems to be re-producable for examination. I would love to develop a search feature in my application if that's possible. Perhaps there's another way to do this? Or perhaps I'm doing something wrong?
*EDIT: It seems functions.contacts.SearchRequest returns little to no users versus public channels/public groups. There shouldn't be a privacy issue because you're searching for publicly set/identifiable data, first name, last name, username, phone number (if public/set to everybody), etc.

python 3 - jack-client - using write_midi_event - jack keeps sending the midi event forever

I try to use python jack-client module to send a program change midi when I click on a button
here is a simplified version of the code :
def process_callback(frames: int):
global midiUi
if(midiUi is not None):
midiUi.process_callback(frames)
class MidiUi:
def __init__(self):
self.client = jack.Client('MidiUi')
self.client.set_process_callback(process_callback)
self.client.activate()
def sendProgramChange(self):
self.midiQueue.append([0xC0,0])
def process_callback(self,frames: int):
while(len(self.midiQueue)>0):
data = self.midiQueue.pop()
self.outMidiPort.clear_buffer()
buffer = self.outMidiPort.reserve_midi_event(0,len(data))
buffer[:] = bytearray(data)
self.outMidiPort.write_midi_event(0,buffer) # this only happens once yet midi input receives tons of program changes events
#raise jack.CallbackExit
midiUi = MidiUi()
while True:
....
#some button calls midiUi.sendProgramChange()
write_midi_event is called only once when pressing the button,
but apparently the destination midi port receives a continuous flow of midi C0 program changes (unless I call jack.CallbackExit, but then the call back never triggers again)
(I monitor my python script output using jack_midi_dump and midisnoop)
anyone know how to solve this ?
thanks for your help
I now user python-rtmidi for this matter
midiout = rtmidi.MidiOut(rtapi=rtmidi.API_UNIX_JACK)
rtMidiOutputPorts=midiout.get_ports()
then write data to the port
This post may be kind of old and it seems like you've got it figured out, but I did find a solution:
The midi client is sending whatever is in the buffer, which means that things like write_midi_event need to be cleared to stop sending it. Therefore, what helped me was near the beginning of my process, I had;
outport.clear_buffer()
Hope that helps ;)

How to lock virtualbox to get a screenshot through SOAP API

I'm trying to use the SOAP interface of Virtualbox 6.1 from Python to get a screenshot of a machine. I can start the machine but get locking errors whenever I try to retrieve the screen layout.
This is the code:
import zeep
# helper to show the session lock status
def show_lock_state(session_id):
session_state = service.ISession_getState(session_id)
print('current session state:', session_state)
# connect
client = zeep.Client('http://127.0.0.1:18083?wsdl')
service = client.create_service("{http://www.virtualbox.org/}vboxBinding", 'http://127.0.0.1:18083?wsdl')
manager_id = service.IWebsessionManager_logon('fakeuser', 'fakepassword')
session_id = service.IWebsessionManager_getSessionObject(manager_id)
# get the machine id and start it
machine_id = service.IVirtualBox_findMachine(manager_id, 'Debian')
progress_id = service.IMachine_launchVMProcess(machine_id, session_id, 'gui')
service.IProgress_waitForCompletion(progress_id, -1)
print('Machine has been started!')
show_lock_state(session_id)
# unlock and then lock to be sure, doesn't have any effect apparently
service.ISession_unlockMachine(session_id)
service.IMachine_lockMachine(machine_id, session_id, 'Shared')
show_lock_state(session_id)
console_id = service.ISession_getConsole(session_id)
display_id = service.IConsole_getDisplay(console_id)
print(service.IDisplay_getGuestScreenLayout(display_id))
The machine is started properly but the last line gives the error VirtualBox error: rc=0x80004001 which from what I read around means locked session.
I tried to release and acquire the lock again, but even though it succeeds the error remains. I went through the documentation but cannot find other types of locks that I'm supposed to use, except the Write lock which is not usable here since the machine is running. I could not find any example in any language.
I found an Android app called VBoxManager with this SOAP screenshot capability.
Running it through a MITM proxy I reconstructed the calls it performs and wrote them as the Zeep equivalent. In case anyone is interested in the future, the last lines of the above script are now:
console_id = service.ISession_getConsole(session_id)
display_id = service.IConsole_getDisplay(console_id)
resolution = service.IDisplay_getScreenResolution(display_id, 0)
print(f'display data: {resolution}')
image_data = service.IDisplay_takeScreenShotToArray(
display_id,
0,
resolution['width'],
resolution['height'],
'PNG')
with open('screenshot.png', 'wb') as f:
f.write(base64.b64decode(image_data))

Change Device Wallpaper in Python/Kivy

I have a simple app and,among other things, I need this app to be able to change the wallpaper of a device on Android.
Now, I've looked around on the net and pyjnius seems like the obvious choice. The problem now is I don't know the first thing about java but a quick google search produces the WallpaperManager as something I could use.
Here's the question: How do I implement that wallpaper manager functionality on my kivy app with pyjnius.
Again, NOT a java dev so don't shoot
I don't know Java either but after examining some java examples i generated a solution. Don't forget to add SET_WALLPAPER permission to your buildozer.spec file. You also need to get storage permission to have this example work.
from jnius import autoclass, cast
PythonActivity = autoclass('org.kivy.android.PythonActivity')
try:
Environment = autoclass("android.os.Environment")
path = Environment.getExternalStorageDirectory().toString()
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
context = cast('android.content.Context', currentActivity.getApplicationContext())
File = autoclass('java.io.File')
file = File(path+"/test.jpg")
BitmapFactory = autoclass('android.graphics.BitmapFactory')
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath())
WallpaperManager = autoclass('android.app.WallpaperManager')
manager = WallpaperManager.getInstance(context)
manager.setBitmap(bitmap)
except Exception as e:
print(e)

Bluetoothctl or gatttool for BLE notifications from multiple devices

I have read many questions on the topic but found no information on how to best (or if it is even possible) to receive notifications from more than 1 device at a time using any library or API (preferably command line or Python library).
After connecting to different devices e.g. Heart Rate monitor and Phone, or two HR monitors, is there a way to receive data from 1 service from each device at the same time?
EDIT:
I have managed to connect different devices of the same characteristics and been able to get notifications from them using Bluetoothctl (part of Bluez) so long as I don't request the same service, which answers my question partially; still, does anyone know of a better way to do this?
1) First of all there is a github python project that does just that in Linux on Raspberry Pi: https://github.com/IanHarvey/bluepy
2) Second this snipet from Anthony Chiu uses that API to communicate with multiple devices using notifications:
from bluepy.btle import Scanner, DefaultDelegate, Peripheral
import threading
class NotificationDelegate(DefaultDelegate):
def __init__(self, number):
DefaultDelegate.__init__(self)
self.number = number
def handleNotification(self, cHandle, data):
print 'Notification:\nConnection:'+str(self.number)+ \nHandler:'+str(cHandle)+'\nMsg:'+data
bt_addrs = ['00:15:83:00:45:98', '00:15:83:00:86:72']
connections = []
connection_threads = []
scanner = Scanner(0)
class ConnectionHandlerThread (threading.Thread):
def __init__(self, connection_index):
threading.Thread.__init__(self)
self.connection_index = connection_index
def run(self):
connection = connections[self.connection_index]
connection.setDelegate(NotificationDelegate(self.connection_index))
while True:
if connection.waitForNotifications(1):
connection.writeCharacteristic(37, 'Thank you for the notification!')
while True:
print'Connected: '+str(len(connection_threads))
print 'Scanning...'
devices = scanner.scan(2)
for d in devices:
print(d.addr)
if d.addr in bt_addrs:
p = Peripheral(d)
connections.append(p)
t = ConnectionHandlerThread(len(connections)-1)
t.start()
connection_threads.append(t)
3) I will just write the manual connection option with bluetoothctl that you probably tried. Since it wasn't listed here, I will add that too:
**Manual connection with bluetoothctl: ** To get the list of characteristics you can use the “list-attributes” command after establing connection and entering Generic Attribute Submenu through menu gatt in bluetoothctl, which should print the same list as above:
list-attributes 00:61:61:15:8D:60
To read an attribute you first select it, with the -you guessed it- “select-attribute” command:
select-attribute /org/bluez/hci0/dev_00_61_61_15_8D_60/service000a/char000b
After that you can issue the “read” command, without any parameters.
To read a characteristic continuously (if characteristic supports it) , use the “notify” command:
notify on
PS: This is my first answer on stackoverflow :)
I am also new to BLE, so bear with me. Am interested in your project, any links / contact are appreciated :)
You can find me on alexandrudancu.com

Resources