]> git.alsa-project.org Git - alsa-lib.git/commitdiff
More better fix for linked start/stop
authorTakashi Iwai <tiwai@suse.de>
Tue, 13 Mar 2007 01:52:33 +0000 (02:52 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 13 Mar 2007 01:52:33 +0000 (02:52 +0100)
Instead of link_fd, more generic callback link_slaves is introduced.
This is called for linking the slave streams as the source to the
given master stream.

13 files changed:
src/pcm/pcm.c
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c
src/pcm/pcm_file.c
src/pcm/pcm_generic.c
src/pcm/pcm_generic.h
src/pcm/pcm_hooks.c
src/pcm/pcm_hw.c
src/pcm/pcm_ioplug.c
src/pcm/pcm_local.h
src/pcm/pcm_multi.c
src/pcm/pcm_plugin.c

index 03d3bd120c194336258c7db52042ac1f872c2a3b..07c7a00514398e68ca7cffd63c841ef89ec44ce1 100644 (file)
@@ -6314,15 +6314,6 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm,
 
 #ifndef DOC_HIDDEN
 
-int _snd_pcm_link_descriptors(snd_pcm_t *pcm, int *fds, int count,
-                             int (**failed)(snd_pcm_t *, int))
-{
-       assert(pcm);
-       if (pcm->fast_ops->link_fd)
-               return pcm->fast_ops->link_fd(pcm, fds, count, failed);
-       return -ENOSYS;
-}
-
 int _snd_pcm_poll_descriptor(snd_pcm_t *pcm)
 {
        assert(pcm);
index 4b97909f45086c4dd5ddc1fe9e60dcf564b33e0c..c18bc6a83b196c45e0308d1f26e06760c187db28 100644 (file)
@@ -757,8 +757,8 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
        .rewind = snd_pcm_dmix_rewind,
        .forward = snd_pcm_dmix_forward,
        .resume = snd_pcm_direct_resume,
-       .link_fd = NULL,
        .link = NULL,
+       .link_slaves = NULL,
        .unlink = NULL,
        .writei = snd_pcm_mmap_writei,
        .writen = snd_pcm_mmap_writen,
index cb205d30e8c9ed5ad9b836a0089d65b188d2bf0e..e9af739679a9b195b020f39e9e8eb50955004658 100644 (file)
@@ -562,8 +562,8 @@ static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
        .rewind = snd_pcm_dshare_rewind,
        .forward = snd_pcm_dshare_forward,
        .resume = snd_pcm_direct_resume,
-       .link_fd = NULL,
        .link = NULL,
+       .link_slaves = NULL,
        .unlink = NULL,
        .writei = snd_pcm_mmap_writei,
        .writen = snd_pcm_mmap_writen,
index 8c11562dd2b363e75cf4c3d44d5f93e308df6e59..24c8e949b2fbe12b71f14df9e86aa47955dd1e9d 100644 (file)
@@ -452,8 +452,8 @@ static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
        .rewind = snd_pcm_dsnoop_rewind,
        .forward = snd_pcm_dsnoop_forward,
        .resume = snd_pcm_direct_resume,
-       .link_fd = NULL,
        .link = NULL,
+       .link_slaves = NULL,
        .unlink = NULL,
        .writei = snd_pcm_dsnoop_writei,
        .writen = snd_pcm_dsnoop_writen,
index b75eda7117f88cf7909a73f19aee1ee1a3bebf95..9a53d53145ef7191555c7ab10340400ae507a422 100644 (file)
@@ -373,8 +373,8 @@ static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
        .rewind = snd_pcm_file_rewind,
        .forward = snd_pcm_file_forward,
        .resume = snd_pcm_generic_resume,
-       .link_fd = snd_pcm_generic_link_fd,
        .link = snd_pcm_generic_link,
+       .link_slaves = snd_pcm_generic_link_slaves,
        .unlink = snd_pcm_generic_unlink,
        .writei = snd_pcm_file_writei,
        .writen = snd_pcm_file_writen,
index ffef8fe45fbe6cffeb7bed6c7202449a6fe73ea1..82fe55be3a4afefc08cd437788457826f716b22e 100644 (file)
@@ -197,14 +197,6 @@ snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frame
        return snd_pcm_rewind(generic->slave, frames);
 }
 
-int snd_pcm_generic_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int))
-{
-       snd_pcm_generic_t *generic = pcm->private_data;
-       if (generic->slave->fast_ops->link_fd)
-               return generic->slave->fast_ops->link_fd(generic->slave->fast_op_arg, fds, count, failed);
-       return -ENOSYS;
-}
-
 int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
 {
        snd_pcm_generic_t *generic = pcm1->private_data;
@@ -213,44 +205,12 @@ int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
        return -ENOSYS;
 }
 
-int snd_pcm_generic_link2(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
-{
-       int fds1[16], fds2[16];
-       int (*failed1)(snd_pcm_t *, int) = NULL;
-       int (*failed2)(snd_pcm_t *, int) = NULL;
-       int count1 = _snd_pcm_link_descriptors(pcm1, fds1, 16, &failed1);
-       int count2 = _snd_pcm_link_descriptors(pcm2, fds2, 16, &failed2);
-       int i, err = 0;
-
-       if (count1 < 0)
-               return count1;
-       if (count2 < 0)
-               return count2;
-       for (i = 1; i < count1; i++) {
-               if (fds1[i] < 0)
-                       return 0;
-               if (ioctl(fds1[0], SNDRV_PCM_IOCTL_LINK, fds1[i]) < 0) {
-                       if (failed1 != NULL) {
-                               err = failed1(pcm2, fds1[i]);
-                       } else {
-                               SYSMSG("SNDRV_PCM_IOCTL_LINK failed");
-                               err = -errno;
-                       }
-               }
-       }
-       for (i = 0; i < count2; i++) {
-               if (fds2[i] < 0)
-                       return 0;
-               if (ioctl(fds1[0], SNDRV_PCM_IOCTL_LINK, fds2[i]) < 0) {
-                       if (failed1 != NULL) {
-                               err = failed2(pcm2, fds2[i]);
-                       } else {
-                               SYSMSG("SNDRV_PCM_IOCTL_LINK failed");
-                               err = -errno;
-                       }
-               }
-       }
-       return err;
+int snd_pcm_generic_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
+{
+       snd_pcm_generic_t *generic = pcm->private_data;
+       if (generic->slave->fast_ops->link_slaves)
+               return generic->slave->fast_ops->link_slaves(generic->slave->fast_op_arg, master);
+       return -ENOSYS;
 }
 
 int snd_pcm_generic_unlink(snd_pcm_t *pcm)
index c2339a8ce729b1e00e37be5f504940e01ff248ce..cd92209207fc888e30679a66044216ceb179ee7b 100644 (file)
@@ -50,9 +50,8 @@ int snd_pcm_generic_resume(snd_pcm_t *pcm);
 int snd_pcm_generic_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp);
 snd_pcm_sframes_t snd_pcm_generic_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
 snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
-int snd_pcm_generic_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int)); 
 int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
-int snd_pcm_generic_link2(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
+int snd_pcm_generic_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master);
 int snd_pcm_generic_unlink(snd_pcm_t *pcm);
 snd_pcm_sframes_t snd_pcm_generic_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
 snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
index 860fccf482124d9810eb680d613f7d5ed41f3c7e..ee0f040508c86dc161f27465c438d6bacd347ea9 100644 (file)
@@ -151,8 +151,8 @@ static snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = {
        .rewind = snd_pcm_generic_rewind,
        .forward = snd_pcm_generic_forward,
        .resume = snd_pcm_generic_resume,
-       .link_fd = snd_pcm_generic_link_fd,
        .link = snd_pcm_generic_link,
+       .link_slaves = snd_pcm_generic_link_slaves,
        .unlink = snd_pcm_generic_unlink,
        .writei = snd_pcm_generic_writei,
        .writen = snd_pcm_generic_writen,
index 5dffb494f1b56686c4f3ff642e4c00a2868cca70..198e49f6b62ba186b10a1a1d2dac309e4d8f9713 100644 (file)
@@ -686,41 +686,35 @@ static int snd_pcm_hw_resume(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_hw_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int))
+static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
 {
-       snd_pcm_hw_t *hw = pcm->private_data;
+       snd_pcm_hw_t *hw1 = pcm1->private_data;
+       snd_pcm_hw_t *hw2 = pcm2->private_data;
+       if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) {
+               SYSMSG("SNDRV_PCM_IOCTL_LINK failed");
+               return -errno;
+       }
+       return 0;
+}
 
-       if (count < 1)
+static int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
+{
+       if (master->type != SND_PCM_TYPE_HW) {
+               SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK");
                return -EINVAL;
-       *failed = NULL;
-       fds[0] = hw->fd;
-       return 1;
+       }
+       return hw_link(master, pcm);
 }
 
 static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
 {
-       snd_pcm_hw_t *hw = pcm1->private_data;
-       int fds[16];
-       int (*failed)(snd_pcm_t *, int) = NULL;
-       int count = _snd_pcm_link_descriptors(pcm2, fds, 16, &failed);
-       int i, err = 0;
-
-       if (count < 0)
-               return count;
-       for (i = 0; i < count; i++) {
-               if (fds[i] < 0)
-                       return 0;
-               if (ioctl(hw->fd, SNDRV_PCM_IOCTL_LINK, fds[i]) < 0) {
-                       if (failed != NULL) {
-                               err = failed(pcm2, fds[i]);
-                       } else {
-                               SYSMSG("SNDRV_PCM_IOCTL_LINK failed");
-                               err = -errno;
-                       }
-               }
+       if (pcm2->type != SND_PCM_TYPE_HW) {
+               if (pcm2->fast_ops->link_slaves)
+                       return pcm2->fast_ops->link_slaves(pcm2, pcm1);
+               return -ENOSYS;
        }
-       return err;
-}
+       return hw_link(pcm1, pcm2);
+ }
 
 static int snd_pcm_hw_unlink(snd_pcm_t *pcm)
 {
@@ -1045,8 +1039,8 @@ static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
        .rewind = snd_pcm_hw_rewind,
        .forward = snd_pcm_hw_forward,
        .resume = snd_pcm_hw_resume,
-       .link_fd = snd_pcm_hw_link_fd,
        .link = snd_pcm_hw_link,
+       .link_slaves = snd_pcm_hw_link_slaves,
        .unlink = snd_pcm_hw_unlink,
        .writei = snd_pcm_hw_writei,
        .writen = snd_pcm_hw_writen,
index dbef48e06a745480934a52f6eddd60ae35d63826..b3a3f1ffd27a4c648f9af1543c3a92ca96b5d87a 100644 (file)
@@ -747,8 +747,8 @@ static snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {
        .hwsync = snd_pcm_ioplug_hwsync,
        .delay = snd_pcm_ioplug_delay,
        .resume = snd_pcm_ioplug_resume,
-       .link_fd = NULL,
        .link = NULL,
+       .link_slaves = NULL,
        .unlink = NULL,
        .rewind = snd_pcm_ioplug_rewind,
        .forward = snd_pcm_ioplug_forward,
index e691e6938534b2e3de72512424276d86ec5f10db..afb6b9be2234dd3757fabce9f74e897390acee35 100644 (file)
@@ -152,8 +152,8 @@ typedef struct {
        int (*hwsync)(snd_pcm_t *pcm);
        int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp);
        int (*resume)(snd_pcm_t *pcm);
-       int (*link_fd)(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *, int));
        int (*link)(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
+       int (*link_slaves)(snd_pcm_t *pcm, snd_pcm_t *master);
        int (*unlink)(snd_pcm_t *pcm);
        snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
        snd_pcm_sframes_t (*forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
index 68fcb3b55bdc367c78f710aca2d69893f06c547e..7e1cc1c9b177f16f1d04a903b15707758f5d2b7e 100644 (file)
@@ -45,7 +45,7 @@ typedef struct {
        snd_pcm_t *pcm;
        unsigned int channels_count;
        int close_slave;
-       int linked;
+       snd_pcm_t *linked;
 } snd_pcm_multi_slave_t;
 
 typedef struct {
@@ -57,7 +57,6 @@ typedef struct {
        unsigned int slaves_count;
        unsigned int master_slave;
        snd_pcm_multi_slave_t *slaves;
-       int slave_link_master;
        unsigned int channels_count;
        snd_pcm_multi_channel_t *channels;
 } snd_pcm_multi_t;
@@ -314,6 +313,21 @@ static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm,
        return 0;
 }
 
+static void reset_links(snd_pcm_multi_t *multi)
+{
+       unsigned int i;
+
+       for (i = 0; i < multi->slaves_count; ++i) {
+               if (multi->slaves[i].linked)
+                       snd_pcm_unlink(multi->slaves[i].linked);
+               multi->slaves[0].linked = NULL;
+               if (! i)
+                       continue;
+               if (snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm) >= 0)
+                       multi->slaves[i].linked = multi->slaves[0].pcm;
+       }
+}
+
 static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_multi_t *multi = pcm->private_data;
@@ -331,12 +345,7 @@ static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                        return err;
                }
        }
-       multi->slaves[0].linked = 0;
-       multi->slave_link_master = 0;
-       for (i = 1; i < multi->slaves_count; ++i) {
-               err = snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm);
-               multi->slaves[i].linked = (err >= 0);
-       }
+       reset_links(multi);
        return 0;
 }
 
@@ -352,10 +361,10 @@ static int snd_pcm_multi_hw_free(snd_pcm_t *pcm)
                        err = e;
                if (!multi->slaves[i].linked)
                        continue;
-               multi->slaves[i].linked = 0;
                e = snd_pcm_unlink(slave);
                if (e < 0)
                        err = e;
+               multi->slaves[i].linked = NULL;
        }
        return err;
 }
@@ -421,7 +430,7 @@ static snd_pcm_sframes_t snd_pcm_multi_avail_update(snd_pcm_t *pcm)
 static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
 {
        snd_pcm_multi_t *multi = pcm->private_data;
-       int err = 0;
+       int result = 0, err;
        unsigned int i;
        for (i = 0; i < multi->slaves_count; ++i) {
                /* We call prepare to each slave even if it's linked.
@@ -429,23 +438,23 @@ static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
                 */
                err = snd_pcm_prepare(multi->slaves[i].pcm);
                if (err < 0)
-                       return err;
+                       result = err;
        }
-       return err;
+       return result;
 }
 
 static int snd_pcm_multi_reset(snd_pcm_t *pcm)
 {
        snd_pcm_multi_t *multi = pcm->private_data;
-       int err = 0;
+       int result = 0, err;
        unsigned int i;
        for (i = 0; i < multi->slaves_count; ++i) {
                /* Reset each slave, as well as in prepare */
                err = snd_pcm_reset(multi->slaves[i].pcm);
-               if (err < 0)
-                       return err;
+               if (err < 0) 
+                       result = err;
        }
-       return err;
+       return result;
 }
 
 static int snd_pcm_multi_start(snd_pcm_t *pcm)
@@ -453,6 +462,8 @@ static int snd_pcm_multi_start(snd_pcm_t *pcm)
        snd_pcm_multi_t *multi = pcm->private_data;
        int err = 0;
        unsigned int i;
+       if (multi->slaves[0].linked)
+               return snd_pcm_start(multi->slaves[0].linked);
        for (i = 0; i < multi->slaves_count; ++i) {
                if (multi->slaves[i].linked)
                        continue;
@@ -468,6 +479,8 @@ static int snd_pcm_multi_drop(snd_pcm_t *pcm)
        snd_pcm_multi_t *multi = pcm->private_data;
        int err = 0;
        unsigned int i;
+       if (multi->slaves[0].linked)
+               return snd_pcm_drop(multi->slaves[0].linked);
        for (i = 0; i < multi->slaves_count; ++i) {
                if (multi->slaves[i].linked)
                        continue;
@@ -483,6 +496,8 @@ static int snd_pcm_multi_drain(snd_pcm_t *pcm)
        snd_pcm_multi_t *multi = pcm->private_data;
        int err = 0;
        unsigned int i;
+       if (multi->slaves[0].linked)
+               return snd_pcm_drain(multi->slaves[0].linked);
        for (i = 0; i < multi->slaves_count; ++i) {
                if (multi->slaves[i].linked)
                        continue;
@@ -498,6 +513,8 @@ static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable)
        snd_pcm_multi_t *multi = pcm->private_data;
        int err = 0;
        unsigned int i;
+       if (multi->slaves[0].linked)
+               return snd_pcm_pause(multi->slaves[0].linked, enable);
        for (i = 0; i < multi->slaves_count; ++i) {
                if (multi->slaves[i].linked)
                        continue;
@@ -587,6 +604,8 @@ static int snd_pcm_multi_resume(snd_pcm_t *pcm)
        snd_pcm_multi_t *multi = pcm->private_data;
        int err = 0;
        unsigned int i;
+       if (multi->slaves[0].linked)
+               return snd_pcm_resume(multi->slaves[0].linked);
        for (i = 0; i < multi->slaves_count; ++i) {
                if (multi->slaves[i].linked)
                        continue;
@@ -597,35 +616,31 @@ static int snd_pcm_multi_resume(snd_pcm_t *pcm)
        return err;
 }
 
-static int snd_pcm_multi_link_fd_failed(snd_pcm_t *pcm, int fd)
-{
+static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
+{ 
        snd_pcm_multi_t *multi = pcm->private_data;
-       unsigned int i;
+       unsigned int i, j;
+       int err;
 
        for (i = 0; i < multi->slaves_count; ++i) {
-               if (_snd_pcm_link_descriptor(multi->slaves[i].pcm) != fd)
-                       continue;
-                multi->slaves[i].linked = 0;
+               snd_pcm_unlink(multi->slaves[i].pcm);
+               multi->slaves[i].linked = NULL;
+               err = snd_pcm_link(master, multi->slaves[i].pcm);
+               if (err < 0) {
+                       reset_links(multi);
+                       return err;
+               }
+               multi->slaves[i].linked = master;
        }
        return 0;
 }
 
-static int snd_pcm_multi_link_fd(snd_pcm_t *pcm, int *fds, int count, int (**failed)(snd_pcm_t *pcm, int fd))
-{ 
-       snd_pcm_multi_t *multi = pcm->private_data;
-       unsigned int i;
-
-       if (count < (int)multi->slaves_count)
-               return -ENOMEM;
-       for (i = 0; i < multi->slaves_count; ++i) {
-               if (multi->slaves[i].linked)
-                       snd_pcm_unlink(multi->slaves[i].pcm);
-               fds[i] = _snd_pcm_link_descriptor(multi->slaves[i].pcm);
-               if (i > 0)
-                       multi->slaves[i].linked = 1;
-       }
-       *failed = snd_pcm_multi_link_fd_failed;
-       return multi->slaves_count;
+static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
+{
+       snd_pcm_multi_t *multi = pcm1->private_data;
+       if (multi->slaves[0].pcm->fast_ops->link)
+               return multi->slaves[0].pcm->fast_ops->link(multi->slaves[0].pcm, pcm2);
+       return -ENOSYS;
 }
 
 static int snd_pcm_multi_unlink(snd_pcm_t *pcm)
@@ -635,8 +650,8 @@ static int snd_pcm_multi_unlink(snd_pcm_t *pcm)
 
        for (i = 0; i < multi->slaves_count; ++i) {
                if (multi->slaves[i].linked)
-                       snd_pcm_unlink(multi->slaves[i].pcm);
-               multi->slaves[i].linked = 0;
+                       snd_pcm_unlink(multi->slaves[i].linked);
+               multi->slaves[0].linked = NULL;
        }
        return 0;
 }
@@ -727,8 +742,8 @@ static snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
        .rewind = snd_pcm_multi_rewind,
        .forward = snd_pcm_multi_forward,
        .resume = snd_pcm_multi_resume,
-       .link_fd = snd_pcm_multi_link_fd,
-       .link = snd_pcm_generic_link2,
+       .link = snd_pcm_multi_link,
+       .link_slaves = snd_pcm_multi_link_slaves,
        .unlink = snd_pcm_multi_unlink,
        .avail_update = snd_pcm_multi_avail_update,
        .mmap_commit = snd_pcm_multi_mmap_commit,
index a76020e9ef05ba3814c9f9bde10c4cc997d2fc49..236f9d3640d33a052df8530a60fb294ae44c1d08 100644 (file)
@@ -566,8 +566,8 @@ snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
        .rewind = snd_pcm_plugin_rewind,
        .forward = snd_pcm_plugin_forward,
        .resume = snd_pcm_generic_resume,
-       .link_fd = snd_pcm_generic_link_fd,
        .link = snd_pcm_generic_link,
+       .link_slaves = snd_pcm_generic_link_slaves,
        .unlink = snd_pcm_generic_unlink,
        .writei = snd_pcm_plugin_writei,
        .writen = snd_pcm_plugin_writen,