]> git.sesse.net Git - vlc/blobdiff - modules/audio_output/amem.c
Qt is GPLv2+
[vlc] / modules / audio_output / amem.c
index 23dc23ac1674141de0210c3b2e0110f04e9e96ae..9e9ece62e9ca8ac6b1322b61bb7d94166528d811 100644 (file)
@@ -10,7 +10,7 @@
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
@@ -43,7 +43,7 @@ vlc_module_begin ()
         change_private()
     add_integer ("amem-rate", 44100,
                  N_("Sample rate"), N_("Sample rate"), false)
-        change_integer_range (1, 192000)
+        change_integer_range (1, 352800)
         change_private()
     add_integer ("amem-channels", 2,
                  N_("Channels count"), N_("Channels count"), false)
@@ -55,26 +55,38 @@ vlc_module_end ()
 struct aout_sys_t
 {
     void *opaque;
+    int (*setup) (void **, char *, unsigned *, unsigned *);
+    void (*cleanup) (void *opaque);
+    union
+    {
+        struct
+        {
+            void *setup_opaque;
+        };
+        struct
+        {
+             unsigned rate:18;
+             unsigned channels:14;
+        };
+    };
     void (*play) (void *opaque, const void *data, unsigned count, int64_t pts);
     void (*pause) (void *opaque, int64_t pts);
     void (*resume) (void *opaque, int64_t pts);
     void (*flush) (void *opaque);
     void (*drain) (void *opaque);
     int (*set_volume) (void *opaque, float vol, bool mute);
-    void (*cleanup) (void *opaque);
     float volume;
     bool mute;
+    bool ready;
 };
 
-static void Play (audio_output_t *aout, block_t *block,
-                  mtime_t *restrict drift)
+static void Play (audio_output_t *aout, block_t *block)
 {
     aout_sys_t *sys = aout->sys;
 
     sys->play (sys->opaque, block->p_buffer, block->i_nb_samples,
                block->i_pts);
     block_Release (block);
-    (void) drift;
 }
 
 static void Pause (audio_output_t *aout, bool paused, mtime_t date)
@@ -100,6 +112,8 @@ static int VolumeSet (audio_output_t *aout, float vol)
     aout_sys_t *sys = aout->sys;
 
     sys->volume = vol;
+    if (sys->ready)
+        return 0; /* sys->opaque is not yet defined... */
     return sys->set_volume (sys->opaque, vol, sys->mute) ? -1 : 0;
 }
 
@@ -108,6 +122,8 @@ static int MuteSet (audio_output_t *aout, bool mute)
     aout_sys_t *sys = aout->sys;
 
     sys->mute = mute;
+    if (!sys->ready)
+        return 0; /* sys->opaque is not yet defined... */
     return sys->set_volume (sys->opaque, sys->volume, mute) ? -1 : 0;
 }
 
@@ -132,109 +148,130 @@ static int SoftMuteSet (audio_output_t *aout, bool mute)
     return 0;
 }
 
-typedef int (*vlc_audio_format_cb) (void **, char *, unsigned *, unsigned *);
-
-static int Open (vlc_object_t *obj)
+static void Stop (audio_output_t *aout)
 {
-    audio_output_t *aout = (audio_output_t *)obj;
-    aout_sys_t *sys = malloc (sizeof (*sys));
-    if (unlikely(sys == NULL))
-        return VLC_ENOMEM;
+    aout_sys_t *sys = aout->sys;
 
-    aout->sys = sys;
-    sys->opaque = var_InheritAddress (obj, "amem-data");
-    sys->play = var_InheritAddress (obj, "amem-play");
-    sys->pause = var_InheritAddress (obj, "amem-pause");
-    sys->resume = var_InheritAddress (obj, "amem-resume");
-    sys->flush = var_InheritAddress (obj, "amem-flush");
-    sys->drain = var_InheritAddress (obj, "amem-drain");
-    sys->set_volume = var_InheritAddress (obj, "amem-set-volume");
-    sys->cleanup = NULL; /* defer */
-    sys->volume = 1.;
-    sys->mute = false;
-    if (sys->play == NULL)
-        goto error;
+    if (sys->cleanup != NULL)
+        sys->cleanup (sys->opaque);
+    sys->ready = false;
+}
 
-    vlc_audio_format_cb setup = var_InheritAddress (obj, "amem-setup");
+static int Start (audio_output_t *aout, audio_sample_format_t *fmt)
+{
+    aout_sys_t *sys = aout->sys;
     char format[5] = "S16N";
-    unsigned rate, channels;
+    unsigned channels;
 
-    if (setup != NULL)
+    if (sys->setup != NULL)
     {
-        rate = aout->format.i_rate;
-        channels = aout_FormatNbChannels(&aout->format);
+        channels = aout_FormatNbChannels(fmt);
 
-        if (setup (&sys->opaque, format, &rate, &channels))
-            goto error;
-        /* Only call this callback if setup succeeded */
-        sys->cleanup = var_InheritAddress (obj, "amem-cleanup");
+        sys->opaque = sys->setup_opaque;
+        if (sys->setup (&sys->opaque, format, &fmt->i_rate, &channels))
+            return VLC_EGENERIC;
     }
     else
     {
-        rate = var_InheritInteger (obj, "amem-rate");
-        channels = var_InheritInteger (obj, "amem-channels");
+        fmt->i_rate = sys->rate;
+        channels = sys->channels;
     }
 
-    if (rate == 0 || rate > 192000
-     || channels == 0 || channels > AOUT_CHAN_MAX)
-        goto error;
+    /* Initialize volume (in case the UI changed volume before setup) */
+    sys->ready = true;
+    if (sys->set_volume != NULL)
+        sys->set_volume(sys->opaque, sys->volume, sys->mute);
 
-    /* TODO: amem-format */
-    if (strcmp(format, "S16N"))
+    /* Ensure that format is supported */
+    if (fmt->i_rate == 0 || fmt->i_rate > 192000
+     || channels == 0 || channels > AOUT_CHAN_MAX
+     || strcmp(format, "S16N") /* TODO: amem-format */)
     {
-        msg_Err (aout, "format not supported");
-        goto error;
+        msg_Err (aout, "format not supported: %s, %u channel(s), %u Hz",
+                 format, channels, fmt->i_rate);
+        Stop (aout);
+        return VLC_EGENERIC;
     }
 
     /* channel mapping */
     switch (channels)
     {
         case 1:
-            aout->format.i_physical_channels = AOUT_CHAN_CENTER;
+            fmt->i_physical_channels = AOUT_CHAN_CENTER;
             break;
         case 2:
-            aout->format.i_physical_channels =
-                AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
+            fmt->i_physical_channels = AOUT_CHANS_2_0;
             break;
         case 3:
-            aout->format.i_physical_channels =
-                AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_LFE;
+            fmt->i_physical_channels = AOUT_CHANS_2_1;
             break;
         case 4:
-            aout->format.i_physical_channels =
-                AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
-                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
+            fmt->i_physical_channels = AOUT_CHANS_4_0;
             break;
         case 5:
-            aout->format.i_physical_channels =
-                AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
-                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
+            fmt->i_physical_channels = AOUT_CHANS_5_0;
             break;
         case 6:
-            aout->format.i_physical_channels =
-                AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
-                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
+            fmt->i_physical_channels = AOUT_CHANS_5_1;
             break;
         case 7:
-            aout->format.i_physical_channels =
+            fmt->i_physical_channels =
                 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
                 AOUT_CHAN_REARCENTER | AOUT_CHAN_MIDDLELEFT |
                 AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE;
             break;
         case 8:
-            aout->format.i_physical_channels =
-                AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
-                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
-                AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE;
+            fmt->i_physical_channels = AOUT_CHANS_7_1;
             break;
         default:
-            assert(0);
+            vlc_assert_unreachable();
     }
 
-    aout->format.i_format = VLC_CODEC_S16N;
-    aout->format.i_rate = rate;
-    aout->format.i_original_channels = aout->format.i_physical_channels;
+    fmt->i_format = VLC_CODEC_S16N;
+    fmt->i_original_channels = fmt->i_physical_channels;
+    return VLC_SUCCESS;
+}
+
+static int Open (vlc_object_t *obj)
+{
+    audio_output_t *aout = (audio_output_t *)obj;
+    aout_sys_t *sys = malloc (sizeof (*sys));
+    if (unlikely(sys == NULL))
+        return VLC_ENOMEM;
+
+    void *opaque = var_InheritAddress (obj, "amem-data");
+    sys->setup = var_InheritAddress (obj, "amem-setup");
+    if (sys->setup != NULL)
+    {
+        sys->cleanup = var_InheritAddress (obj, "amem-cleanup");
+        sys->setup_opaque = opaque;
+    }
+    else
+    {
+        sys->cleanup = NULL;
+        sys->opaque = opaque;
+        sys->rate = var_InheritInteger (obj, "amem-rate");
+        sys->channels = var_InheritInteger (obj, "amem-channels");
+    }
+    sys->play = var_InheritAddress (obj, "amem-play");
+    sys->pause = var_InheritAddress (obj, "amem-pause");
+    sys->resume = var_InheritAddress (obj, "amem-resume");
+    sys->flush = var_InheritAddress (obj, "amem-flush");
+    sys->drain = var_InheritAddress (obj, "amem-drain");
+    sys->set_volume = var_InheritAddress (obj, "amem-set-volume");
+    sys->volume = 1.;
+    sys->mute = false;
+    sys->ready = false;
+    if (sys->play == NULL)
+    {
+        free (sys);
+        return VLC_EGENERIC;
+    }
 
+    aout->sys = sys;
+    aout->start = Start;
+    aout->stop = Stop;
+    aout->time_get = NULL;
     aout->play = Play;
     aout->pause = Pause;
     aout->flush = Flush;
@@ -249,10 +286,6 @@ static int Open (vlc_object_t *obj)
         aout->mute_set = SoftMuteSet;
     }
     return VLC_SUCCESS;
-
-error:
-    Close (obj);
-    return VLC_EGENERIC;
 }
 
 static void Close (vlc_object_t *obj)
@@ -260,7 +293,5 @@ static void Close (vlc_object_t *obj)
     audio_output_t *aout = (audio_output_t *)obj;
     aout_sys_t *sys = aout->sys;
 
-    if (sys->cleanup != NULL)
-        sys->cleanup (sys->opaque);
     free (sys);
 }