You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Kivy开发Android实时麦克风输入回传应用?

基于Kivy的Android实时音频回传应用开发需求

需求说明

我想要用Kivy开发一款Android应用,用户点击按钮后即可将麦克风输入实时回传播放。目前已实现将音频输入保存到文件的功能,但无法实现不保存文件的实时回传。做这个是为了开发一款基于Python和socket的音频聊天应用,最终用buildozer导出为.apk文件。

已实现的音频文件录制代码(非目标功能)

from kivy.uix.boxlayout import BoxLayout 
from kivy.uix.label import Label 
from kivy.uix.button import Button 
from kivy.lang import Builder
from kivy.app import App 
from kivy.clock import Clock 
from kivy.uix.textinput import TextInput
from kivy.uix.switch import Switch 
from jnius import autoclass 
Builder.load_string('''
<AudioTool>
    orientation: 'vertical'
    Label:
        id: display_label
        text: '00:00'
    BoxLayout:
        size_hint: 1, .2
        TextInput:
            id: user_input
            text: '5'
            disabled: duration_switch.active == False #TUT 3 IF SWITCH IS OFF TEXTINPUT IS DISABLED 
            on_text: root.enforce_numeric()
              
        Switch:
            id: duration_switch
                        
    BoxLayout:
        Button:
            id: start_button
            text: 'Start Recording'
            on_release: root.startRecording_clock()
 
        Button:
            id: stop_button
            text: 'Stop Recording'
            on_release: root.stopRecording()
            disabled: True
''')
 
class MyRecorder:
    def __init__(self):
        '''Recorder object To access Android Hardware'''
        self.MediaRecorder = autoclass('android.media.MediaRecorder')
        self.AudioSource = autoclass('android.media.MediaRecorder$AudioSource')
        self.OutputFormat = autoclass('android.media.MediaRecorder$OutputFormat')
        self.AudioEncoder = autoclass('android.media.MediaRecorder$AudioEncoder')
 
        # create out recorder
        self.mRecorder = self.MediaRecorder()
        self.mRecorder.setAudioSource(self.AudioSource.MIC)
        self.mRecorder.setOutputFormat(self.OutputFormat.THREE_GPP)
        self.mRecorder.setOutputFile('/sdcard/MYAUDIO.3gp')
        self.mRecorder.setAudioEncoder(self.AudioEncoder.AMR_NB)
        self.mRecorder.prepare()
 
 
 
class AudioApp(App):
    def build(self):
        return AudioTool()
 
 
 
class AudioTool(BoxLayout):
    def __init__(self, **kwargs):
        super(AudioTool, self).__init__(**kwargs)
        
        self.start_button = self.ids['start_button']
        self.stop_button = self.ids['stop_button']
        self.display_label = self.ids['display_label']
        self.switch = self.ids['duration_switch'] # Tutorial 3
        self.user_input = self.ids['user_input']
            
 
    def enforce_numeric(self): 
        '''Make sure the textinput only accepts numbers'''
        if self.user_input.text.isdigit() == False: 
            digit_list = [num for num in self.user_input.text if num.isdigit()]
            self.user_input.text = "".join(digit_list)
 
    def startRecording_clock(self):
        
        self.mins = 0 #Reset the minutes
        self.zero = 1 # Reset if the function gets called more than once
        self.duration = int(self.user_input.text) #Take the input from the user and convert to a number
        Clock.schedule_interval(self.updateDisplay, 1)
        self.start_button.disabled = True # Prevents the user from clicking start again which may crash the program
        self.stop_button.disabled = False
        self.switch.disabled = True #TUT Switch disabled when start is pressed
        Clock.schedule_once(self.startRecording) ## NEW start the recording 
    
    def startRecording(self, dt): #NEW start the recorder
        self.r = MyRecorder()
        self.r.mRecorder.start()
    
    def stopRecording(self):
    
        Clock.unschedule(self.updateDisplay)
        self.r.mRecorder.stop() #NEW RECORDER VID 6
        self.r.mRecorder.release() #NEW RECORDER VID 6
        
        Clock.unschedule(self.startRecording) #NEW stop the recording of audio VID 6 
        self.display_label.text = 'Finished Recording!'
        self.start_button.disabled = False
        self.stop_button.disabled = True #TUT 3
        self.switch.disabled = False #TUT 3 re enable the switch
         
    def updateDisplay(self,dt):   
        if self.switch.active == False:
            if self.zero < 60 and len(str(self.zero)) == 1:
                self.display_label.text = '0' + str(self.mins) + ':0' + str(self.zero)
                self.zero += 1
                
            elif self.zero < 60 and len(str(self.zero)) == 2:
                    self.display_label.text = '0' + str(self.mins) + ':' + str(self.zero)
                    self.zero += 1
            
            elif self.zero == 60:
                self.mins +=1
                self.display_label.text = '0' + str(self.mins) + ':00'
                self.zero = 1
        
        elif self.switch.active == True:
            if self.duration == 0: # 0
                self.display_label.text = 'Recording Finished!'
                self.stopRecording() # NEW VID 6 / THIS ONE LINE SHOULD TAKE CARE OF THE RECORDING NOT STOPPING. 
                #self.start_button.disabled = False # Re enable start
                #self.stop_button.disabled = True # Re disable stop
                #Clock.unschedule(self.updateDisplay) #DELETE FOR VID 6 
                
                #self.switch.disabled = False # Re enable the switch
                
            elif self.duration > 0 and len(str(self.duration)) == 1: # 0-9
                self.display_label.text = '00' + ':0' + str(self.duration)
                self.duration -= 1
 
            elif self.duration > 0 and self.duration < 60 and len(str(self.duration)) == 2: # 0-59
                self.display_label.text = '00' + ':' + str(self.duration)
                self.duration -= 1
 
            elif self.duration >= 60 and len(str(self.duration % 60)) == 1: # EG 01:07
                self.mins = self.duration / 60
                self.display_label.text = '0' + str(self.mins) + ':0' + str(self.duration % 60)
                self.duration -= 1
 
            elif self.duration >= 60 and len(str(self.duration % 60)) == 2: # EG 01:17
                self.mins = self.duration / 60
                self.display_label.text = '0' + str(self.mins) + ':' + str(self.duration % 60)
                self.duration -= 1
 
 
if __name__ == '__main__':
    AudioApp().run()

尝试过的模块及问题

  • pyaudio:无法带着该模块导出apk
  • audiostream:无法正常运行
  • soundcard:无法正常运行

寻求解决方案

正在寻找使用jnius或其他支持Kivy(及Android)的模块的解决方案。


内容的提问来源于stack exchange,提问作者CocaColaCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 23:47:19