1

概要:これは私の最後の問題 ( here ) のフォローアップです。私はすぐにそれについての完全な答えを投稿します。Gstreamer を介して、Python で PS3 Eye からのオーディオ入力をポケットスフィンクスに認識させることができます。正しい alsa デバイス (私の場合は hw:1 ) を指定します。

問題:私の次の問題は、私のマイクが既に使用されており、何かを録音できるようにする必要があるという小さな競合状態に関係しているようです。

次のことを想像してください。

  1. Python デーモンを起動しましたが、現在リッスンしています。
  2. 私はマイクに向かって話し、Hello Scarlett と言いました (Pocketsphinx はキーワードに一致し、すべての入力の記録を開始します)。
  3. オーディオは、/tmp/ ディレクトリの wav ファイルに録音されることを意図しており、無音が検出されるまでそこに留まると想定されています

手順 3 を開始すると、マイクが再び機能しなくなったようです。何が起こったのかを把握するためにいくつかの詳細なオプションを使用して実行しましたが、 /tmp/ ディレクトリを確認するとすべてがわかりました。

pi@scarlettpi ~ $ ls -lta /tmp/ | grep wav
-rw-r--r--   1 pi    pi       0 Aug 13 20:57 fsdgjdspi.wav
pi@scarlettpi ~ $

ファイルサイズは 0 バイトです。何も記録されていません。

strace を使用してプロセスを実行したことを確認し、疑わしいことを確認するには、次のようにします。

pi@scarlettpi ~ $ strace -p 12416 | tee -a pi.strace.log 2>&1
Process 12416 attached - interrupt to quit
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, -1) = 1 ([{fd=3, revents=POLLIN}])
read(3, "\1\0\0\0\0\0\0\0", 16)         = 8
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, -1) = 1 ([{fd=3, revents=POLLIN}])
read(3, "\1\0\0\0\0\0\0\0", 16)         = 8
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, -1) = 1 ([{fd=3, revents=POLLIN}])
read(3, "\1\0\0\0\0\0\0\0", 16)         = 8
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, -1) = 1 ([{fd=3, revents=POLLIN}])
read(3, "\1\0\0\0\0\0\0\0", 16)         = 8
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, -1) = 1 ([{fd=3, revents=POLLIN}])
read(3, "\1\0\0\0\0\0\0\0", 16)         = 8
ioctl(7, 0x80044121, 0xbebd764c)        = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
futex(0x1e47f34, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x1e47f30, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0x1e45218, FUTEX_WAKE_PRIVATE, 1) = 1
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
ioctl(7, 0x80044121, 0xbebd764c)        = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
gettimeofday({1376379565, 54761}, NULL) = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
open("/usr/local/lib/python2.7/dist-packages/pi-0.1.0-py2.7.egg/static/sounds/pi-listening.wav", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
open("/usr/local/lib/python2.7/dist-packages/pi-0.1.0-py2.7.egg/static/sounds/pi-listening.wav", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
lstat64("/tmp/tmpkTS2Fwpi.wav", 0xbebd73a0) = -1 ENOENT (No such file or directory)
socketpair(PF_FILE, SOCK_STREAM, 0, [19, 20]) = 0
fcntl64(19, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
fcntl64(20, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
brk(0x1f20000)                          = 0x1f20000
socketpair(PF_FILE, SOCK_STREAM, 0, [21, 22]) = 0
fcntl64(21, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
fcntl64(22, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
write(1, "Bossjones Note: Technically we'r"..., 97) = 97
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
stat64("/usr/share/alsa/alsa.conf", {st_mode=S_IFREG|0644, st_size=9184, ...}) = 0
open("/dev/snd/controlC1", O_RDONLY|O_CLOEXEC) = 23
fcntl64(23, F_SETFD, FD_CLOEXEC)        = 0
ioctl(23, UI_DEV_CREATE, 0xbebd6dd4)    = 0
close(23)                               = 0
open("/dev/snd/controlC1", O_RDWR|O_CLOEXEC) = 23
fcntl64(23, F_SETFD, FD_CLOEXEC)        = 0
ioctl(23, USBDEVFS_CONTROL or USBDEVFS_CONTROL32, 0xbebd6f74) = 0
ioctl(23, 0x40045532, 0xbebd6fac)       = 0
open("/dev/snd/pcmC1D0c", O_RDWR|O_NONBLOCK|O_CLOEXEC) = -1 EBUSY (Device or resource busy)
close(23)                               = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
open("/tmp/tmpkTS2Fwpi.wav", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 23
fstat64(23, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6f6f000
_llseek(23, 0, [0], SEEK_SET)           = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
stat64("/usr/share/alsa/alsa.conf", {st_mode=S_IFREG|0644, st_size=9184, ...}) = 0
open("/dev/snd/controlC1", O_RDONLY|O_CLOEXEC) = 24
fcntl64(24, F_SETFD, FD_CLOEXEC)        = 0
ioctl(24, UI_DEV_CREATE, 0xbebd6dd4)    = 0
close(24)                               = 0
open("/dev/snd/controlC1", O_RDWR|O_CLOEXEC) = 24
fcntl64(24, F_SETFD, FD_CLOEXEC)        = 0
ioctl(24, USBDEVFS_CONTROL or USBDEVFS_CONTROL32, 0xbebd6f74) = 0
ioctl(24, 0x40045532, 0xbebd6fac)       = 0
open("/dev/snd/pcmC1D0c", O_RDWR|O_NONBLOCK|O_CLOEXEC) = -1 EBUSY (Device or resource busy)
close(24)                               = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(1, " * Listening closely...\n", 24) = 24
clock_gettime(CLOCK_MONOTONIC, {355220, 267713756}) = 0
clock_gettime(CLOCK_MONOTONIC, {355220, 268557726}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 1 ([{fd=3, revents=POLLIN}])
read(3, "-\0\0\0\0\0\0\0", 16)          = 8
clock_gettime(CLOCK_MONOTONIC, {355220, 273415554}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
read(3, 0xbebd828c, 16)                 = -1 EAGAIN (Resource temporarily unavailable)
clock_gettime(CLOCK_MONOTONIC, {355220, 277294417}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 280380308}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 282305240}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 284684156}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 286915077}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 290111964}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 291641910}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 293437847}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355220, 295553772}) = 0
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 10705) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {355231, 13213798}) = 0
write(1, " # cancel False False\n", 22) = 22
write(1, " * Not a word in the past 10 sec"..., 49) = 49
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
close(23)                               = 0
munmap(0xb6f6f000, 4096)                = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
gettimeofday({1376379576, 186258}, NULL) = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
open("/usr/local/lib/python2.7/dist-packages/pi-0.1.0-py2.7.egg/static/sounds/pi-cancel.wav", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
open("/usr/local/lib/python2.7/dist-packages/pi-0.1.0-py2.7.egg/static/sounds/pi-cancel.wav", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
ioctl(7, 0x80044121, 0xbebd7ac4)        = -1 EPIPE (Broken pipe)
futex(0xe78524, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0xe78520, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0xe78500, FUTEX_WAKE_PRIVATE, 1)  = 1
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
futex(0x1b82fec, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x1b82fe8, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0x1ac5618, FUTEX_WAKE_PRIVATE, 1) = 1
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 1 ([{fd=3, revents=POLLIN}])
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 1 ([{fd=3, revents=POLLIN}])
read(3, "*\0\0\0\0\0\0\0", 16)          = 8
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
read(3, 0xbebd828c, 16)                 = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, 0) = 0 (Timeout)
poll([{fd=3, events=POLLIN}, {fd=6, events=POLLIN}], 2, -1^C <unfinished ...>
Process 12416 detached

質問:これを機能させるにはどうすればよいですか?

これがpythonコードです。

Listener.py:

import pi
from pi.becore import ScarlettConfig
from recorder import Recorder
from brain import Brain

import os
import json
import tempfile
#import sys

import pygtk
pygtk.require('2.0')
import gtk
import gobject
import pygst
pygst.require('0.10')
gobject.threads_init()
import gst

scarlett_config=ScarlettConfig()

class Listener:
  def __init__(self, gobject, gst):
    self.failed = 0

    self.pipeline = gst.parse_launch(' ! '.join(['alsasrc device=' + scarlett_config.gimmie('audio_input_device'),
                                               'queue',
                                               'audioconvert',
                                               'audioresample',
                                               'queue',
                                               'vader name=vader auto-threshold=true',
                                               'pocketsphinx lm=' + scarlett_config.gimmie('LM') + ' dict=' + scarlett_config.gimmie('DICT') + ' hmm=' + scarlett_config.gimmie('HMM') + ' name=listener',
                                               'fakesink dump=1']))
    listener = self.pipeline.get_by_name('listener')
    listener.connect('result', self.__result__)
    listener.set_property('configured', True)
    print "KEYWORDS WE'RE LOOKING FOR: " + scarlett_config.gimmie('ourkeywords')

    bus = self.pipeline.get_bus()
    bus.add_signal_watch()
    bus.connect('message::application', self.__application_message__)
    self.pipeline.set_state(gst.STATE_PLAYING)

  def result(self, hyp, uttid):
    if hyp in scarlett_config.gimmie('ourkeywords'):
      self.failed = 0
      self.listen()
    else:
      self.failed += 1
      if self.failed > 4:
        pi.speak("" + scarlett_config.gimmie('scarlett_owner') + ", if you need me, just say my name.")
        self.failed = 0

  def listen(self):
    self.pipeline.set_state(gst.STATE_PAUSED)
    pi.play('pi-listening')
    Recorder(self)

  def cancel_listening(self):
    pi.play('pi-cancel')
    self.pipeline.set_state(gst.STATE_PLAYING)

###[ ........MUSIC SUFF HERE........ ]

  def __result__(self, listener, text, uttid):
    struct = gst.Structure('result')
    struct.set_value('hyp', text)
    struct.set_value('uttid', uttid)
    listener.post_message(gst.message_new_application(listener, struct))

  def __application_message__(self, bus, msg):
    msgtype =  msg.structure.get_name()
    if msgtype == 'result':
      self.result(msg.structure['hyp'], msg.structure['uttid'])

これがrecorder.pyです:

import pi
from pi.becore import ScarlettConfig

import os
import tempfile

import pygtk
pygtk.require('2.0')
import gtk
import gobject
import pygst
pygst.require('0.10')
gobject.threads_init()
import gst

scarlett_config=ScarlettConfig()

class Recorder:
  def __init__(self, listener):
    self.listener = listener
    self.started = False
    self.finished = False
    self.recording = tempfile.mktemp(suffix='pi.wav')

    self.pipeline = gst.parse_launch(' ! '.join(['alsasrc device=' + scarlett_config.gimmie('audio_input_device'),
                                                 'queue',
                                                 'audioconvert',
                                                 'queue',
                                                 'audioresample',
                                                 'queue',
                                                 'vader name=vader auto-threshold=false',
                                                 'fakesink dump=1']))

    print "Bossjones Note: What is the current PIPLINE state BEFORE we're recording" + self.pipeline.get_state()

    self.recorder = gst.parse_launch(' ! '.join(['alsasrc device=' + scarlett_config.gimmie('audio_input_device'),
                                                 'queue',
                                                 'audioconvert',
                                                 'audioresample',
                                                 'audio/x-raw-int,rate=16000,width=16,channels=1,endianness=(int)1234',
                                                 'wavenc',
                                                 'filesink location=' + self.recording]))

    print "Bossjones Note: Technically we're suppose to be recording to this location: " + self.recording
    vader = self.pipeline.get_by_name('vader')
    vader.connect('vader_start', self.__start__)
    vader.connect('vader_stop', self.__stop__)

    bus = self.pipeline.get_bus()
    bus.add_signal_watch()
    bus.connect('message::application', self.__application_message__)
    self.pipeline.set_state(gst.STATE_PLAYING)
    self.recorder.set_state(gst.STATE_PLAYING)

    print " * Listening closely..."
    gobject.timeout_add_seconds(10, self.cancel)

  def start(self):
    self.started = True
    print " * Recording..."

  def stop(self):
    print " * (silence)"
    gobject.timeout_add_seconds(1, self.stop_now)

  def stop_now(self):
    print " # stop_now"
    if self.finished == True:
      self.listener.cancel_listening()
      return

    self.finished = True
    print " * Stored recording to ", self.recording
    self.pipeline.set_state(gst.STATE_NULL)
    self.recorder.set_state(gst.STATE_NULL)

    print " * Converting to FLAC..."
    os.system("ffmpeg -i %s -y %s" % (self.recording, self.recording))
    #os.unlink(self.recording)
    os.system("sox %s %s.final.wav noisered %s/static/noise.prof 0.21" % (self.recording, self.recording, pi.PWD))
    os.system("flac -f --best --sample-rate 16000 -o %s.flac %s.final.wav 2>/dev/null"  % (self.recording, self.recording))
    os.unlink(self.recording + ".final.wav")
    print " * Done."
    self.listener.answer(self.recording + '.flac')

  def cancel(self):
    print " # cancel", self.finished, self.started
    if self.finished == True:
      print " # cancel - noop"
      return

    if self.started == False:
      self.finished = True
      print " * Not a word in the past 10 seconds, cancelling"
      self.pipeline.set_state(gst.STATE_NULL)
      self.recorder.set_state(gst.STATE_NULL)
      self.listener.cancel_listening()

  def __start__(self, vader, arg0):
    print " # vader:start"
    struct = gst.Structure('vader_start')
    struct.set_value('arg0', arg0)
    vader.post_message(gst.message_new_application(vader, struct))

  def __stop__(self, vader, arg0):
    print " # vader:stop"
    struct = gst.Structure('vader_stop')
    struct.set_value('arg0', arg0)
    vader.post_message(gst.message_new_application(vader, struct))

  def __application_message__(self, bus, msg):
    msgtype = msg.structure.get_name()
    if msgtype == 'vader_stop':
      self.stop()
    elif msgtype == 'vader_start':
      self.start()

これをデバッグする最善の方法について考えていますか?

ありがとう。

4

1 に答える 1