changeset 383:abb9c3dedec2 macness

ITunesSVRemote methods to query playback position and state
author Dan Stowell <dan.stowell@eecs.qmul.ac.uk>
date Mon, 18 Oct 2010 14:44:28 +0100
parents fad5611ef9db
children be237d380f5f
files main/MainWindow.cpp osx/svitunes.h osx/svitunes.mm
diffstat 3 files changed, 120 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/main/MainWindow.cpp	Mon Oct 18 13:59:08 2010 +0100
+++ b/main/MainWindow.cpp	Mon Oct 18 14:44:28 2010 +0100
@@ -2173,6 +2173,8 @@
             emit hideSplash();
         QMessageBox::critical(this, tr("Failed to open file"),
                   tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
+    }else{
+        m_iTunes->updatePlayerState();
     }
     }
 }
--- a/osx/svitunes.h	Mon Oct 18 13:59:08 2010 +0100
+++ b/osx/svitunes.h	Mon Oct 18 14:44:28 2010 +0100
@@ -23,7 +23,6 @@
 /**
 * Class to handle communication with a running iTunes program on the system.
 * Only implemented for Mac at present, since using applescript communication.
-* Pseudo-singleton - one instance expected to be owned by SVApplication.
 */
 class ITunesSVRemote : QObject
 {
@@ -31,15 +30,46 @@
     
     public:
         
-        //LATER: bool iTunesRunning();
+        ITunesSVRemote() :
+            m_playerState(STATE_UNKNOWN),
+            m_playerPos(0)
+            { }
+        virtual ~ITunesSVRemote() { }
     
         // Returns a list containing [posixpath, genre]
         QStringList getNowPlaying();
+        
+        // Queries iTunes about player state and stores results locally
+        void updatePlayerState();
     
-        //LATER: QStringList iTunesSelectedPaths();
+        // Whether the app is running. Only correct if updatePlayerState() recently invoked.
+        bool isRunning();
+        
+        // Whether the app is playing back. Only correct if updatePlayerState() recently invoked.
+        bool isPlaying();
+        
+        // Playback position in seconds. Only correct if updatePlayerState() recently invoked.
+        unsigned int playerPos();
     
-//    private:
-//        QString qt_mac_NSStringToQString(const NSString *nsstr);
+    protected:
+        
+        enum {
+            STATE_UNKNOWN, // before ever querying
+            STATE_CLOSED,  // application not running
+            // The rest correspond to states reported by iTunes itself:
+            STATE_STOPPED, 
+            STATE_PLAYING, 
+            STATE_PAUSED,
+            STATE_FASTFORWARDING, 
+            STATE_REWINDING
+            };
+        
+        // itunes has a set of states: {playing, stopped, ...}.
+        // we also use "unknown" before checking, 
+        // and "closed" if iTunes isn't running.
+        int m_playerState;
+        unsigned int m_playerPos; // itunes only tells us seconds
+    
 };
 
 #endif
--- a/osx/svitunes.mm	Mon Oct 18 13:59:08 2010 +0100
+++ b/osx/svitunes.mm	Mon Oct 18 14:44:28 2010 +0100
@@ -18,6 +18,10 @@
 
 #import <Foundation/Foundation.h>
 
+#include <iostream>
+#include <cstdio>
+
+// private helpful function:
 QString qt_mac_NSStringToQString(const NSString *nsstr)
 {
     NSRange range;
@@ -67,11 +71,87 @@
     NSAppleEventDescriptor *eventDesc = [scriptObject executeAndReturnError: &errorDict];
     NSString *nsResultString = [eventDesc stringValue];
     
-    NSLog(@"iTunesNowPlayingPath: ");
-    NSLog(nsResultString);
-    
     QString resultString = qt_mac_NSStringToQString(nsResultString);
     
     [scriptObject release];
     return resultString.split(QChar('\n'));
 }
+
+void ITunesSVRemote::updatePlayerState(){
+    NSDictionary *errorDict;
+    NSAppleScript *scriptObject = [[NSAppleScript alloc]    initWithSource:@" \
+tell application \"System Events\" to set iTunesIsRunning to (name of processes) contains \"iTunes\" \n\
+if iTunesIsRunning is false then return \"\" \n\
+\
+tell application \"iTunes\" \n\
+	if player state is not playing then \n\
+		set playpos to 0 \n\
+	else \n\
+		set playpos to player position \n\
+	end if \n\
+    \
+    return (player state as text) & \"\n\" & (playpos) \n\
+end tell \n\
+"
+    ];
+    
+    NSLog([scriptObject source]);
+    
+    [scriptObject compileAndReturnError: &errorDict];
+    
+    if(![scriptObject isCompiled]){
+        NSLog(@"SV ERROR: applescript object not compiled");
+        NSLog([errorDict description]);
+    }
+    
+    NSAppleEventDescriptor *eventDesc = [scriptObject executeAndReturnError: &errorDict];
+    NSString *nsResultString = [eventDesc stringValue];
+    
+    QString resultString = qt_mac_NSStringToQString(nsResultString);
+    
+    if(resultString==""){
+        m_playerState = STATE_CLOSED;
+            std::cerr << "ITunesSVRemote::updatePlayerState() IT IS CLOSED" << std::endl;
+    }else{
+        QStringList results = resultString.split(QChar('\n'));
+        
+        if(results.size() != 2){
+            std::cerr << "ITunesSVRemote::updatePlayerState() ERROR: results not in expected format:" 
+                       << resultString.toStdString() << std::endl;
+            [scriptObject release];
+            return;
+        }
+        
+        if(results[0]=="playing")
+            m_playerState = STATE_PLAYING;
+        else if(results[0]=="paused")
+            m_playerState = STATE_PAUSED;
+        else if(results[0]=="stopped")
+            m_playerState = STATE_STOPPED;
+        else if(results[0]=="fast forwarding")
+            m_playerState = STATE_FASTFORWARDING;
+        else if(results[0]=="rewinding")
+            m_playerState = STATE_REWINDING;
+
+        if(m_playerState == STATE_PLAYING){
+            // store a record of the current playback position
+            m_playerPos = results[1].toInt();
+            std::cerr << "ITunesSVRemote::updatePlayerState() got playback position as " 
+                        << m_playerPos << std::endl;
+        }
+    }
+    
+    [scriptObject release];
+}
+
+bool ITunesSVRemote::isRunning(){
+    return (m_playerState != STATE_UNKNOWN) && (m_playerState != STATE_CLOSED);
+}
+
+bool ITunesSVRemote::isPlaying(){
+    return (m_playerState == STATE_PLAYING);
+}
+
+unsigned int ITunesSVRemote::playerPos(){
+    return m_playerPos;
+}