def process_compressed_data(self): self.unzipped_input += self.decompressor.decompress(self.data) self.data = "" while self.hasNextObj(): reqObject = self.read_next_object_from_unzipped() if reqObject != None: self.logger.debug("Packet with class: {0}".format( reqObject['class'])) self.logger.debug("packet with content:\n{0}".format( pprint.pformat(reqObject, width=40))) # first handle speech stuff if 'refId' in reqObject: # if the following holds, this packet is an answer to a request by a plugin if reqObject[ 'refId'] == self.plugin_lastAceId and self.current_running_plugin != None: if self.current_running_plugin.waitForResponse != None: # just forward the object to the # don't change it's refId, further requests must reference last FinishSpeech self.logger.info("Forwarding object to plugin") self.plugin_lastAceId = None self.current_running_plugin.response = reqObject self.current_running_plugin.waitForResponse.set() if ObjectIsCommand(reqObject, StartSpeechRequest) or ObjectIsCommand( reqObject, StartSpeechDictation): self.logger.info("New start of speech received") startSpeech = None if ObjectIsCommand(reqObject, StartSpeechDictation): dictation = True startSpeech = StartSpeechDictation(reqObject) else: dictation = False startSpeech = StartSpeechRequest(reqObject) decoder = speex.Decoder() encoder = flac.Encoder() speexUsed = False if startSpeech.codec == StartSpeech.CodecSpeex_WB_Quality8Value: decoder.initialize(mode=speex.SPEEX_MODEID_WB) encoder.initialize(16000, 1, 16) speexUsed = True elif startSpeech.codec == StartSpeech.CodecSpeex_NB_Quality7Value: decoder.initialize(mode=speex.SPEEX_MODEID_NB) encoder.initialize(16000, 1, 16) speexUsed = True elif startSpeech.codec == StartSpeech.CodecPCM_Mono_16Bit_8000HzValue: encoder.initialize(8000, 1, 16) elif startSpeech.codec == StartSpeech.CodecPCM_Mono_16Bit_11025HzValue: encoder.initialize(11025, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_16000HzValue: encoder.initialize(16000, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_22050HzValue: encoder.initialize(22050, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_32000HzValue: encoder.initialize(32000, 1, 16) # we probably need resampling for sample rates other than 16kHz... self.speech[startSpeech.aceId] = (decoder if speexUsed else None, encoder, dictation) elif ObjectIsCommand(reqObject, SpeechPacket): self.logger.info("Decoding speech packet") speechPacket = SpeechPacket(reqObject) (decoder, encoder, dictation) = self.speech[speechPacket.refId] if decoder: pcm = decoder.decode(speechPacket.packets) else: pcm = SpeechPacket.data # <- probably data... if pcm encoder.encode(pcm) elif reqObject['class'] == 'StartCorrectedSpeechRequest': self.process_recognized_speech( { u'hypotheses': [{ 'confidence': 1.0, 'utterance': str.lower(reqObject['properties']['utterance']) }] }, reqObject['aceId'], False) elif ObjectIsCommand(reqObject, FinishSpeech): self.logger.info("End of speech received") finishSpeech = FinishSpeech(reqObject) (decoder, encoder, dictation) = self.speech[finishSpeech.refId] if decoder: decoder.destroy() encoder.finish() flacBin = encoder.getBinary() encoder.destroy() del self.speech[finishSpeech.refId] self.logger.info("Sending flac to google for recognition") self.httpClient.make_google_request( flacBin, finishSpeech.refId, dictation, language=self.assistant.language, allowCurses=True) elif ObjectIsCommand(reqObject, CancelRequest): # this is probably called when we need to kill a plugin # wait for thread to finish a send cancelRequest = CancelRequest(reqObject) if cancelRequest.refId in self.speech: del self.speech[cancelRequest.refId] self.send_object(CancelSucceeded(cancelRequest.aceId)) elif ObjectIsCommand(reqObject, GetSessionCertificate): getSessionCertificate = GetSessionCertificate(reqObject) response = GetSessionCertificateResponse( getSessionCertificate.aceId) response.caCert = caCert.as_der() response.sessionCert = serverCert.as_der() self.send_object(response) elif ObjectIsCommand(reqObject, CreateSessionInfoRequest): # how does a positive answer look like? createSessionInfoRequest = CreateSessionInfoRequest( reqObject) fail = CommandFailed(createSessionInfoRequest.aceId) fail.reason = "Not authenticated" fail.errorCode = 0 self.send_object(fail) #self.send_plist({"class":"SessionValidationFailed", "properties":{"errorCode":"UnsupportedHardwareVersion"}, "aceId": str(uuid.uuid4()), "refId":reqObject['aceId'], "group":"com.apple.ace.system"}) elif reqObject['class'] == 'CreateAssistant': #create a new assistant helper = Assistant() c = self.dbConnection.cursor() noError = True try: c.execute( "insert into assistants(assistantId, assistant) values (?,?)", (helper.assistantId, helper)) self.dbConnection.commit() except sqlite3.Error, e: noError = False c.close() if noError: self.assistant = helper self.send_plist({ "class": "AssistantCreated", "properties": { "speechId": str(uuid.uuid4()), "assistantId": helper.assistantId }, "group": "com.apple.ace.system", "callbacks": [], "aceId": str(uuid.uuid4()), "refId": reqObject['aceId'] }) else: self.send_plist({ "class": "CommandFailed", "properties": { "reason": "Database error", "errorCode": 2, "callbacks": [] }, "aceId": str(uuid.uuid4()), "refId": reqObject['aceId'], "group": "com.apple.ace.system" }) elif reqObject['class'] == 'SetAssistantData': # fill assistant if self.assistant != None: c = self.dbConnection.cursor() objProperties = reqObject['properties'] self.assistant.censorSpeech = objProperties[ 'censorSpeech'] self.assistant.timeZoneId = objProperties['timeZoneId'] #self.assistant.language = objProperties['language'] if self.lang != None: self.assistant.language = self.lang else: self.assistant.language = objProperties['language'] self.assistant.region = objProperties['region'] c.execute( "update assistants set assistant = ? where assistantId = ?", (self.assistant, self.assistant.assistantId)) self.dbConnection.commit() c.close() elif reqObject['class'] == 'LoadAssistant': c = self.dbConnection.cursor() c.execute( "select assistant from assistants where assistantId = ?", (reqObject['properties']['assistantId'], )) self.dbConnection.commit() result = c.fetchone() if result == None: self.send_plist({ "class": "AssistantNotFound", "aceId": str(uuid.uuid4()), "refId": reqObject['aceId'], "group": "com.apple.ace.system" }) else: self.assistant = result[0] self.send_plist({ "class": "AssistantLoaded", "properties": { "version": "20111216-32234-branches/telluride?cnxn=293552c2-8e11-4920-9131-5f5651ce244e", "requestSync": False, "dataAnchor": "removed" }, "aceId": str(uuid.uuid4()), "refId": reqObject['aceId'], "group": "com.apple.ace.system" }) c.close() elif reqObject['class'] == 'DestroyAssistant': c = self.dbConnection.cursor() c.execute("delete from assistants where assistantId = ?", (reqObject['properties']['assistantId'], )) self.dbConnection.commit() c.close() self.send_plist({ "class": "AssistantDestroyed", "properties": { "assistantId": reqObject['properties']['assistantId'] }, "aceId": str(uuid.uuid4()), "refId": reqObject['aceId'], "group": "com.apple.ace.system" }) elif reqObject['class'] == 'StartRequest': #this should also be handeled by special plugins, so lets call the plugin handling stuff self.process_recognized_speech( { 'hypotheses': [{ 'utterance': reqObject['properties']['utterance'], 'confidence': 1.0 }] }, reqObject['aceId'], False)
def received_plist(self, plist): self.logger.debug("Got packet with class: {0}".format(plist['class'])) self.logger.debug("packet with content:\n{0}".format( pprint.pformat(plist, width=40))) # first handle speech stuff if 'refId' in plist: # if the following holds, this packet is an answer to a request by a plugin if plist[ 'refId'] == self.plugin_lastAceId and self.current_running_plugin != None: if self.current_running_plugin.waitForResponse != None: # just forward the object to the # don't change it's refId, further requests must reference last FinishSpeech self.logger.debug("Forwarding object to plugin") self.plugin_lastAceId = None self.current_running_plugin.response = plist if plist[ 'class'] != "StartRequest" else plist['properties'][ 'utterance'] self.current_running_plugin.waitForResponse.set() return if ObjectIsCommand(plist, StartSpeechRequest) or ObjectIsCommand( plist, StartSpeechDictation): self.logger.debug("New start of speech received") startSpeech = None if ObjectIsCommand(plist, StartSpeechDictation): dictation = True startSpeech = StartSpeechDictation(plist) else: dictation = False startSpeech = StartSpeechRequest(plist) decoder = speex.Decoder() encoder = flac.Encoder() speexUsed = False if startSpeech.codec == StartSpeech.CodecSpeex_WB_Quality8Value: decoder.initialize(mode=speex.SPEEX_MODEID_WB) encoder.initialize(16000, 1, 16) speexUsed = True elif startSpeech.codec == StartSpeech.CodecSpeex_NB_Quality7Value: decoder.initialize(mode=speex.SPEEX_MODEID_NB) encoder.initialize(16000, 1, 16) speexUsed = True elif startSpeech.codec == StartSpeech.CodecPCM_Mono_16Bit_8000HzValue: encoder.initialize(8000, 1, 16) elif startSpeech.codec == StartSpeech.CodecPCM_Mono_16Bit_11025HzValue: encoder.initialize(11025, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_16000HzValue: encoder.initialize(16000, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_22050HzValue: encoder.initialize(22050, 1, 16) elif startSpeech.coded == StartSpeech.CodecPCM_Mono_16Bit_32000HzValue: encoder.initialize(32000, 1, 16) # we probably need resampling for sample rates other than 16kHz... self.speech[startSpeech.aceId] = (decoder if speexUsed else None, encoder, dictation) elif ObjectIsCommand(plist, SpeechPacket): self.logger.debug("Decoding speech packet") speechPacket = SpeechPacket(plist) if speechPacket.refId in self.speech: (decoder, encoder, dictation) = self.speech[speechPacket.refId] if decoder: pcm = decoder.decode(speechPacket.packets) else: pcm = SpeechPacket.data # <- probably data... if pcm encoder.encode(pcm) else: self.logger.debug( "Got a speech packet that did not match any current request" ) elif plist['class'] == 'StartCorrectedSpeechRequest': self.process_recognized_speech( { u'hypotheses': [{ 'confidence': 1.0, 'utterance': plist['properties']['utterance'] }] }, plist['aceId'], False) elif ObjectIsCommand(plist, FinishSpeech): self.logger.debug("End of speech received") finishSpeech = FinishSpeech(plist) if finishSpeech.refId in self.speech: (decoder, encoder, dictation) = self.speech[finishSpeech.refId] if decoder: decoder.destroy() flacBin = None if encoder: encoder.finish() flacBin = encoder.getBinary() encoder.destroy() del self.speech[finishSpeech.refId] if flacBin != None: self.logger.info("Sending flac to google for recognition") try: self.current_google_request = self.httpClient.make_google_request( flacBin, finishSpeech.refId, dictation, language=self.assistant.language, allowCurses=True) except (AttributeError, TypeError): self.logger.warning( "Unable to find language record for this assistant. Try turning Siri off and then back on." ) else: self.logger.info("There was no speech") else: self.logger.debug( "Got a finish speech packet that did not match any current request" ) elif ObjectIsCommand(plist, CancelRequest): # this is probably called when we need to kill a plugin # wait for thread to finish a send self.logger.debug("Should cancel current request") cancelRequest = CancelRequest(plist) if cancelRequest.refId in self.speech: (decoder, encoder, dictation) = self.speech[cancelRequest.refId] if decoder: decoder.destroy() if encoder: encoder.finish() encoder.destroy() del self.speech[cancelRequest.refId] if self.current_google_request != None: self.current_google_request.cancel() # if a google request is running (follow up listening..., plugin might get killed there by user) if self.current_running_plugin != None: if self.current_running_plugin.waitForResponse != None: self.current_running_plugin._abortPluginRun() self.current_running_plugin.waitForResponse.set() # if a plugin is running (processing, but not waiting for data from the device we kill it) if self.current_running_plugin != None: if self.current_running_plugin.waitForResponse == None: self.current_running_plugin._abortPluginRun() self.send_object(CancelSucceeded(cancelRequest.aceId)) elif ObjectIsCommand(plist, RollbackRequest): pass elif ObjectIsCommand(plist, SyncChunk): chunk = SyncChunk(plist) previous = self.syncAnchors[ chunk.key] if chunk.key in self.syncAnchors else None if previous != None: if previous.generation != chunk.preGen: chunkDenied = SyncChunkDenied(chunk.aceId) self.send_object(chunkDenied) return current = SyncAnchor() current.generation = chunk.postGen current.value = chunk.postGen current.validity = chunk.validity current.key = chunk.key self.syncAnchors[current.key] = current chunkAccepted = SyncChunkAccepted(chunk.aceId) chunkAccepted.current = current self.send_object(chunkAccepted) pass elif ObjectIsCommand(plist, GetSessionCertificate): getSessionCertificate = GetSessionCertificate(plist) sessionCA_DER = crypto.dump_certificate(crypto.FILETYPE_ASN1, self.server.sessionCACert) sessionCert_DER = crypto.dump_certificate(crypto.FILETYPE_ASN1, self.server.sessionCert) response = GetSessionCertificateResponse( getSessionCertificate.aceId, sessionCA_DER, sessionCert_DER) self.send_object(response) elif ObjectIsCommand(plist, CreateSessionInfoRequest): # how does a positive answer look like? createSessionInfoRequest = CreateSessionInfoRequest(plist) #success = CreateSessionInfoResponse(createSessionInfoRequest.aceId) #success.sessionInfo = biplist.Data("\x01\x02BLABLABLBALBALBALBALBALBALBALBA") #success.validityDuration = 9600 #self.send_object(success) fail = CommandFailed(createSessionInfoRequest.aceId) fail.reason = "Not authenticated" fail.errorCode = 0 self.send_object(fail) ##self.send_plist({"class":"SessionValidationFailed", "properties":{"errorCode":"UnsupportedHardwareVersion"}, "aceId": str(uuid.uuid4()), "refId":plist['aceId'], "group":"com.apple.ace.system"}) elif ObjectIsCommand(plist, CreateAssistant): createAssistant = CreateAssistant(plist) #create a new assistant helper = Assistant() helper.assistantId = str.upper(str(uuid.uuid4())) helper.language = createAssistant.language helper.activationToken = createAssistant.activationToken helper.connectionType = createAssistant.connectionType helper.validationData = createAssistant.validationData c = self.dbConnection.cursor() noError = True try: c.execute( "insert into assistants(assistantId, assistant) values (?,?)", (helper.assistantId, helper)) self.dbConnection.commit() except sqlite3.Error: noError = False c.close() if noError: self.assistant = helper assiCreatedCMD = AssistantCreated(createAssistant.aceId) assiCreatedCMD.assistantId = helper.assistantId assiCreatedCMD.speechId = str(uuid.uuid4()) self.send_object(assiCreatedCMD) else: cmdFailed = CommandFailed(createAssistant.aceId) cmdFailed.reason = "Database Error" cmdFailed.errorCode = 2 self.send_object(cmdFailed) elif ObjectIsCommand(plist, SetAssistantData): setAssistantData = SetAssistantData(plist) # fill assistant if self.assistant != None: try: c = self.dbConnection.cursor() assi_id = self.assistant.assistantId self.assistant.initializeFromPlist( setAssistantData.to_plist()) self.assistant.assistantId = assi_id #Record the user firstName and nickName try: self.assistant.firstName = self.assistant.meCards[ 0].firstName.encode("utf-8") except: self.assistant.firstName = u'' try: self.assistant.nickName = self.assistant.meCards[ 0].nickName.encode("utf-8") except: self.assistant.nickName = u'' #Done recording c.execute( "update assistants set assistant = ? where assistantId = ?", (self.assistant, self.assistant.assistantId)) self.dbConnection.commit() c.close() except: cmdFailed = CommandFailed(setAssistantData.aceId) cmdFailed.reason = "Database Error" cmdFailed.errorCode = 2 self.send_object(cmdFailed) self.logger.exception( "Database Error on setting assistant data") else: cmdFailed = CommandFailed(setAssistantData.aceId) cmdFailed.reason = "Assistant to set data not found" cmdFailed.errorCode = 2 self.send_object(cmdFailed) self.logger.warning( "Trying to set assistant data without having a valid assistant" ) elif ObjectIsCommand(plist, LoadAssistant): loadAssistant = LoadAssistant(plist) try: c = self.dbConnection.cursor() c.execute( "select assistant from assistants where assistantId = ?", (loadAssistant.assistantId, )) self.dbConnection.commit() result = c.fetchone() if result == None: self.send_object(AssistantNotFound(loadAssistant.aceId)) self.logger.warning("Assistant not found in database!!") else: self.assistant = result[0] #update assistant from LoadAssistant self.assistant.language = loadAssistant.language self.assistant.connectionType = loadAssistant.connectionType if self.assistant.language == '' or self.assistant.language == None: self.logger.error( "No language is set for this assistant") c.execute( "delete from assistants where assistantId = ?", (plist['properties']['assistantId'], )) self.dbConnection.commit() cmdFailed = CommandFailed(loadAssistant.aceId) cmdFailed.reason = "Database error Assistant not found or language settings" cmdFailed.errorCode = 2 self.send_object(cmdFailed) else: loaded = AssistantLoaded(loadAssistant.aceId) loaded.version = "20111216-32234-branches/telluride?cnxn=293552c2-8e11-4920-9131-5f5651ce244e" loaded.requestSync = 0 try: loaded.dataAnchor = self.assistant.anchor except: loaded.dataAnchor = "removed" self.send_object(loaded) c.close() except: self.send_object(AssistantNotFound(loadAssistant.aceId)) self.logger.warning("Database error on fetching assistant") elif ObjectIsCommand(plist, DestroyAssistant): destroyAssistant = DestroyAssistant(plist) try: c = self.dbConnection.cursor() c.execute("delete from assistants where assistantId = ?", (plist['properties']['assistantId'], )) self.dbConnection.commit() c.close() destroyed = AssistantDestroyed(destroyAssistant.aceId) destroyed.assistantId = destroyAssistant.assistantId self.send_object(destroyed) except: self.send_object(AssistantNotFound(destroyAssistant.aceId)) self.logger.error("Database error on deleting assistant") elif ObjectIsCommand(plist, StartRequest): startRequest = StartRequest(plist) #this should also be handeled by special plugins, so lets call the plugin handling stuff self.process_recognized_speech( { 'hypotheses': [{ 'utterance': startRequest.utterance, 'confidence': 1.0 }] }, startRequest.aceId, False) pass